diff --git a/client/angular/.editorconfig b/client/angular/.editorconfig new file mode 100644 index 0000000..150aa39 --- /dev/null +++ b/client/angular/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.ts] +quote_type = single + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/client/angular/.gitignore b/client/angular/.gitignore new file mode 100644 index 0000000..5f131d1 --- /dev/null +++ b/client/angular/.gitignore @@ -0,0 +1,10 @@ +/.angular +/.idea +/.vscode/* +!/.vscode/extensions.json +/dist +/node_modules +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.DS_Store diff --git a/client/angular/README.md b/client/angular/README.md new file mode 100644 index 0000000..a16ecae --- /dev/null +++ b/client/angular/README.md @@ -0,0 +1,95 @@ +# Angular Spreadsheet Collaborative Editing + +This example demonstrates real-time collaborative editing in the Syncfusion Angular Spreadsheet. Multiple users can edit the same workbook, and supported actions are synchronized through the Collaboration Server. + +## Prerequisites + +- Node.js +- Redis Server +- ASP.NET Core Redis Collaboration Server, or access to the configured hosted Collaboration Server + +## Install dependencies + +```bash +npm install +``` + +## Configure the Collaboration Server + +The Collaboration Server URL is defined in: + +```text +src/components/spreadsheet-editor/spreadsheet-editor.component.ts +``` + +Update `serviceUrl` when a different Collaboration Server endpoint is used. + +## Run the application + +```bash +npm start +``` + +Open the URL displayed by Angular, normally: + +```text +http://localhost:4200/ +``` + +When the page opens without an `id` query parameter, the client generates a room ID and updates the URL. Open the complete URL in another browser tab or window to join the same collaboration room. + +Example: + +```text +http://localhost:4200/?id=sample-room +``` + +## Project structure + +```text +src/ +|-- app/ +| |-- app.config.ts +| |-- app.css +| |-- app.html +| `-- app.ts +|-- components/ +| `-- spreadsheet-editor/ +| |-- spreadsheet-editor.component.css +| |-- spreadsheet-editor.component.html +| |-- spreadsheet-editor.component.ts +| `-- spreadsheet-editor-adapter.ts +|-- index.html +|-- main.ts +`-- styles.css +``` + +## How it works + +1. The Angular Spreadsheet starts with collaborative editing enabled. +2. The client obtains or generates a room ID from the URL. +3. The adapter imports the latest workbook and room version from the server. +4. `CollaborationClient` connects through SignalR and joins the room. +5. Local Spreadsheet actions are sent from the `actionComplete` event. +6. Remote actions are applied through `SpreadsheetEditorAdapter.applyRemoteAction`. + +## Build + +```bash +npm run build +``` + +## Important packages + +- `@syncfusion/ej2-angular-spreadsheet` +- `@syncfusion/ej2-collaborator` +- `@microsoft/signalr` +- `@syncfusion/ej2-tailwind3-theme` + +## Troubleshooting + +If clients do not synchronize, verify that the Collaboration Server is reachable, Redis is running, all clients use the same room ID, and the browser console has no SignalR or CORS errors. + +## License + +Refer to the license file in the parent repository. diff --git a/client/angular/angular.json b/client/angular/angular.json new file mode 100644 index 0000000..d59dc59 --- /dev/null +++ b/client/angular/angular.json @@ -0,0 +1,63 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "angular-spreadsheet-collaborative-editing": { + "projectType": "application", + "schematics": {}, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular/build:application", + "options": { + "browser": "src/main.ts", + "tsConfig": "tsconfig.app.json", + "assets": [ + { + "glob": "**/*", + "input": "public" + } + ], + "styles": ["src/styles.css"] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "1MB", + "maximumError": "2MB" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular/build:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-spreadsheet-collaborative-editing:build:production" + }, + "development": { + "buildTarget": "angular-spreadsheet-collaborative-editing:build:development" + } + }, + "defaultConfiguration": "development" + } + } + } + }, + "cli": { + "analytics": false + } +} diff --git a/client/angular/package.json b/client/angular/package.json new file mode 100644 index 0000000..ebea787 --- /dev/null +++ b/client/angular/package.json @@ -0,0 +1,31 @@ +{ + "name": "angular-spreadsheet-collaborative-editing", + "version": "1.0.0", + "private": true, + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "watch": "ng build --watch --configuration development" + }, + "dependencies": { + "@angular/common": "^22.2.0", + "@angular/compiler": "^22.2.0", + "@angular/core": "^22.2.0", + "@angular/forms": "^22.2.0", + "@angular/platform-browser": "^22.2.0", + "@angular/router": "^22.2.0", + "@microsoft/signalr": "^9.0.0", + "@syncfusion/ej2-angular-spreadsheet": "35.1.37", + "@syncfusion/ej2-collaborator": "35.1.37", + "@syncfusion/ej2-tailwind3-theme": "35.1.37", + "rxjs": "~7.8.0", + "tslib": "^2.3.0" + }, + "devDependencies": { + "@angular/build": "^22.2.0", + "@angular/cli": "^22.2.0", + "@angular/compiler-cli": "^22.2.0", + "typescript": "~6.0.2" + } +} diff --git a/client/angular/src/app/app.config.ts b/client/angular/src/app/app.config.ts new file mode 100644 index 0000000..67fec86 --- /dev/null +++ b/client/angular/src/app/app.config.ts @@ -0,0 +1,5 @@ +import { ApplicationConfig } from '@angular/core'; + +export const appConfig: ApplicationConfig = { + providers: [] +}; diff --git a/client/angular/src/app/app.css b/client/angular/src/app/app.css new file mode 100644 index 0000000..789f20c --- /dev/null +++ b/client/angular/src/app/app.css @@ -0,0 +1,8 @@ +:host { + display: block; + width: 100%; +} + +.app-container { + width: 100%; +} diff --git a/client/angular/src/app/app.html b/client/angular/src/app/app.html new file mode 100644 index 0000000..05963a4 --- /dev/null +++ b/client/angular/src/app/app.html @@ -0,0 +1,3 @@ +
+ +
diff --git a/client/angular/src/app/app.ts b/client/angular/src/app/app.ts new file mode 100644 index 0000000..714660e --- /dev/null +++ b/client/angular/src/app/app.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; +import { SpreadsheetEditorComponent } from '../components/spreadsheet-editor/spreadsheet-editor.component'; + +@Component({ + selector: 'app-root', + standalone: true, + imports: [SpreadsheetEditorComponent], + templateUrl: './app.html', + styleUrl: './app.css' +}) +export class App {} diff --git a/client/angular/src/components/spreadsheet-editor/spreadsheet-editor-adapter.ts b/client/angular/src/components/spreadsheet-editor/spreadsheet-editor-adapter.ts new file mode 100644 index 0000000..db4e92e --- /dev/null +++ b/client/angular/src/components/spreadsheet-editor/spreadsheet-editor-adapter.ts @@ -0,0 +1,83 @@ +import type { + ICollaborationActionData, + ICollaborationProvider +} from '@syncfusion/ej2-collaborator'; +import { SpreadsheetComponent } from '@syncfusion/ej2-angular-spreadsheet'; + +interface ImportFileResponse { + sfdt: string; + version: number; +} + +export class SpreadsheetEditorAdapter + implements ICollaborationProvider { + public currentRoomName: string = ''; + + public constructor( + private spreadsheet: SpreadsheetComponent, + private serviceUrl: string, + private currentUser: string + ) { + this.serviceUrl = serviceUrl.endsWith('/') + ? serviceUrl + : serviceUrl + '/'; + } + + public async loadFromServer( + fileName: string, + roomName: string + ): Promise { + const response: Response = await fetch( + this.serviceUrl + 'api/CollaborativeEditing/ImportFile', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ fileName, roomName }) + } + ); + + if (!response.ok) { + throw new Error('Failed to load the workbook.'); + } + + const data: ImportFileResponse = + JSON.parse(await response.text()); + + this.currentRoomName = roomName; + this.spreadsheet.collaborativeEditingModule.updateRoomInfo( + roomName, + data.version, + this.serviceUrl + 'api/CollaborativeEditing/' + ); + this.spreadsheet.collaborativeEditingModule.setLocalUser( + this.currentUser + ); + this.spreadsheet.openFromJson({ file: data.sfdt }); + } + + public sendActionToServer(action: unknown): void { + if (!action) { + return; + } + + this.spreadsheet.collaborativeEditingModule.sendActionToServer( + action + ); + } + + public applyRemoteAction( + action: string, + data: ICollaborationActionData + ): void { + if (!data) { + return; + } + + this.spreadsheet.collaborativeEditingModule.applyRemoteAction( + action, + data.payload + ); + } +} diff --git a/client/angular/src/components/spreadsheet-editor/spreadsheet-editor.component.css b/client/angular/src/components/spreadsheet-editor/spreadsheet-editor.component.css new file mode 100644 index 0000000..fe8bbc5 --- /dev/null +++ b/client/angular/src/components/spreadsheet-editor/spreadsheet-editor.component.css @@ -0,0 +1,4 @@ +:host { + display: block; + width: 100%; +} diff --git a/client/angular/src/components/spreadsheet-editor/spreadsheet-editor.component.html b/client/angular/src/components/spreadsheet-editor/spreadsheet-editor.component.html new file mode 100644 index 0000000..2f52023 --- /dev/null +++ b/client/angular/src/components/spreadsheet-editor/spreadsheet-editor.component.html @@ -0,0 +1,7 @@ + + diff --git a/client/angular/src/components/spreadsheet-editor/spreadsheet-editor.component.ts b/client/angular/src/components/spreadsheet-editor/spreadsheet-editor.component.ts new file mode 100644 index 0000000..b074c2b --- /dev/null +++ b/client/angular/src/components/spreadsheet-editor/spreadsheet-editor.component.ts @@ -0,0 +1,91 @@ +import { Component, ViewChild } from '@angular/core'; +import { + CollaborativeEditingHandlerService, + SpreadsheetComponent, + SpreadsheetModule +} from '@syncfusion/ej2-angular-spreadsheet'; +import { CollaborationClient } from '@syncfusion/ej2-collaborator'; +import { SpreadsheetEditorAdapter } from './spreadsheet-editor-adapter'; + +const serviceUrl: string = + 'https://appservice-267100-e9c8cxaab6a2dfeu.centralindia-01.azurewebsites.net/'; +const currentUser: string = 'John'; + +function getRoomName(): string { + const currentUrl: URL = new URL(window.location.href); + let roomName: string = ( + currentUrl.searchParams.get('id') || '' + ).trim(); + + if (!roomName) { + roomName = Math.random().toString(32).slice(2); + currentUrl.searchParams.set('id', roomName); + window.history.replaceState( + window.history.state, + '', + currentUrl.pathname + currentUrl.search + currentUrl.hash + ); + } + + return roomName; +} + +@Component({ + selector: 'app-spreadsheet-editor', + standalone: true, + imports: [SpreadsheetModule], + providers: [CollaborativeEditingHandlerService], + templateUrl: './spreadsheet-editor.component.html', + styleUrl: './spreadsheet-editor.component.css' +}) +export class SpreadsheetEditorComponent { + @ViewChild('spreadsheet') + public spreadsheetObj!: SpreadsheetComponent; + + private adapter: SpreadsheetEditorAdapter | null = null; + private client: CollaborationClient | null = null; + private initialized: boolean = false; + + public async created(): Promise { + if (!this.spreadsheetObj || this.initialized) { + return; + } + + this.initialized = true; + const roomName: string = getRoomName(); + const adapter = new SpreadsheetEditorAdapter( + this.spreadsheetObj, + serviceUrl, + currentUser + ); + + try { + await adapter.loadFromServer('Sample', roomName); + + const client = new CollaborationClient(adapter, { + serviceUrl, + connectionType: 'signalr', + currentUser + }); + + this.adapter = adapter; + this.client = client; + await client.joinRoomAsync(roomName); + + console.log( + '[Collaborative Editing] Joined room', + roomName + ); + } catch (error) { + this.initialized = false; + console.error( + '[Collaborative Editing] Failed to join the room.', + error + ); + } + } + + public actionComplete(args: unknown): void { + this.adapter?.sendActionToServer(args); + } +} diff --git a/client/angular/src/index.html b/client/angular/src/index.html new file mode 100644 index 0000000..c855029 --- /dev/null +++ b/client/angular/src/index.html @@ -0,0 +1,12 @@ + + + + + Angular Spreadsheet Collaborative Editing + + + + + + + diff --git a/client/angular/src/main.ts b/client/angular/src/main.ts new file mode 100644 index 0000000..7fd415e --- /dev/null +++ b/client/angular/src/main.ts @@ -0,0 +1,6 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { appConfig } from './app/app.config'; +import { App } from './app/app'; + +bootstrapApplication(App, appConfig) + .catch((error: unknown) => console.error(error)); diff --git a/client/angular/src/styles.css b/client/angular/src/styles.css new file mode 100644 index 0000000..01a5d10 --- /dev/null +++ b/client/angular/src/styles.css @@ -0,0 +1,11 @@ +@import '../node_modules/@syncfusion/ej2-tailwind3-theme/styles/tailwind3.css'; + +html, +body { + height: 100%; + margin: 0; +} + +body { + font-family: "Segoe UI", Arial, sans-serif; +} diff --git a/client/angular/tsconfig.app.json b/client/angular/tsconfig.app.json new file mode 100644 index 0000000..5b9d3c5 --- /dev/null +++ b/client/angular/tsconfig.app.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"] +} diff --git a/client/angular/tsconfig.json b/client/angular/tsconfig.json new file mode 100644 index 0000000..452682e --- /dev/null +++ b/client/angular/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "outDir": "./dist/out-tsc", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "sourceMap": true, + "declaration": false, + "experimentalDecorators": true, + "moduleResolution": "bundler", + "importHelpers": true, + "target": "ES2022", + "module": "preserve", + "lib": ["ES2022", "dom"] + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/client/react/README.md b/client/react/README.md new file mode 100644 index 0000000..cc6a6e0 --- /dev/null +++ b/client/react/README.md @@ -0,0 +1,179 @@ +# React Spreadsheet Collaborative Editing + +This example demonstrates real-time collaborative editing in the Syncfusion React Spreadsheet. Multiple users can edit the same workbook simultaneously, and the changes are synchronized through the Collaboration Server. + +## Prerequisites + +Before running the React client, ensure that the following software and services are available: + +- Node.js +- Redis Server +- ASP.NET Core Redis Collaboration Server + +The Collaboration Server and Redis Server must be running before starting the React application. + +## Installing dependencies + +Navigate to the React client folder: + +```bash +cd client/react +``` + +Install the required dependencies: + +```bash +npm install +``` + +The `@syncfusion/ej2-collaborator` package is listed separately because the React Spreadsheet package does not install the collaboration client automatically. + +The `@microsoft/signalr` package is required by the collaboration client for SignalR communication with the ASP.NET Core Collaboration Server. + +## Configuring the Collaboration Server URL + +Open `src/App.tsx` and update the following URL when required: + +```ts +const serviceUrl: string = + 'https://appservice-267100-e9c8cxaab6a2dfeu.centralindia-01.azurewebsites.net/'; +``` + +The URL must point to the running ASP.NET Core Collaboration Server. + +## Running the application + +Start the React development server: + +```bash +npm run dev +``` + +Open the URL displayed by Vite. The default URL is: + +```text +http://localhost:5173/ +``` + +## Testing collaborative editing + +When the application is opened without an `id` query parameter, the React client automatically generates a room name and adds it to the URL. + +For example: + +```text +http://localhost:5173/?id=room-name +``` + +Copy the complete URL and open it in another browser window or tab. Clients using the same room ID collaborate on the same workbook. + +The sample uses the following participant name: + +```ts +const currentUser: string = 'John'; +``` + +## How the sample works + +1. The Spreadsheet is initialized with collaborative editing enabled. +2. The `CollaborativeEditingHandler` service is injected into the Spreadsheet. +3. The client obtains or generates a room name from the URL. +4. `SpreadsheetEditorAdapter.loadFromServer` imports the latest workbook and room version from the server. +5. `CollaborationClient` connects to the server using SignalR. +6. The client joins the collaboration room by calling `joinRoomAsync`. +7. Local Spreadsheet actions are sent to the server from the `actionComplete` event. +8. Remote actions received through the collaboration client are applied to the Spreadsheet. + +## Theme configuration + +The Syncfusion Tailwind 3 theme is imported in `src/App.css`: + +```css +@import "@syncfusion/ej2-tailwind3-theme/styles/tailwind3.css"; +``` + +The stylesheet is loaded in `src/App.tsx`: + +```ts +import './App.css'; +``` + +Do not remove the `App.css` import. Without the theme stylesheet, the Spreadsheet output will not render correctly. + +## Project structure + +```text +client/react/ +|-- src/ +| |-- App.css +| |-- App.tsx +| |-- main.tsx +| `-- SpreadsheetEditorAdapter.ts +|-- index.html +|-- package.json +|-- README.md +|-- tsconfig.app.json +|-- tsconfig.json +|-- tsconfig.node.json +`-- vite.config.ts +``` + +## Production build + +Create a production build by running: + +```bash +npm run build +``` + +Preview the production build locally: + +```bash +npm run preview +``` + +## Troubleshooting + +### The collaborator package cannot be resolved + +Ensure `@syncfusion/ej2-collaborator` is present in `package.json`, and then run: + +```bash +npm install +``` + +### The SignalR package cannot be resolved + +Ensure `@microsoft/signalr` is present in `package.json`, and then run: + +```bash +npm install +``` + +### The Spreadsheet output is not styled correctly + +Confirm that `src/App.tsx` contains: + +```ts +import './App.css'; +``` + +Also confirm that `src/App.css` contains: + +```css +@import "@syncfusion/ej2-tailwind3-theme/styles/tailwind3.css"; +``` + +### Clients do not receive synchronized changes + +Verify the following items: + +- Redis Server is running. +- The ASP.NET Core Collaboration Server is running. +- The `serviceUrl` value points to the correct server. +- All clients use the same room ID in the URL. +- The browser console does not contain SignalR connection or CORS errors. + +## License + +This project is licensed under the terms provided in the repository license file. diff --git a/client/react/index.html b/client/react/index.html new file mode 100644 index 0000000..ec86aff --- /dev/null +++ b/client/react/index.html @@ -0,0 +1,15 @@ + + + + + + + React Spreadsheet Collaborative Editing + + + +
+ + + + \ No newline at end of file diff --git a/client/react/package.json b/client/react/package.json new file mode 100644 index 0000000..0cb6355 --- /dev/null +++ b/client/react/package.json @@ -0,0 +1,29 @@ +{ + "name": "react-spreadsheet-collaborative-editing", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "oxlint", + "preview": "vite preview" + }, + "dependencies": { + "@microsoft/signalr": "^9.0.0", + "@syncfusion/ej2-collaborator": "35.1.37", + "@syncfusion/ej2-react-spreadsheet": "35.1.37", + "@syncfusion/ej2-tailwind3-theme": "35.1.37", + "react": "^19.2.8", + "react-dom": "^19.2.8" + }, + "devDependencies": { + "@types/node": "^24.13.3", + "@types/react": "^19.2.18", + "@types/react-dom": "^19.2.7", + "@vitejs/plugin-react": "^6.1.1", + "oxlint": "^1.81.0", + "typescript": "~6.0.2", + "vite": "^8.3.0" + } +} diff --git a/client/react/src/App.css b/client/react/src/App.css new file mode 100644 index 0000000..5b40715 --- /dev/null +++ b/client/react/src/App.css @@ -0,0 +1 @@ +@import "@syncfusion/ej2-tailwind3-theme/styles/tailwind3.css"; diff --git a/client/react/src/App.tsx b/client/react/src/App.tsx new file mode 100644 index 0000000..e32f1e6 --- /dev/null +++ b/client/react/src/App.tsx @@ -0,0 +1,130 @@ +import { useRef } from 'react'; +import { + CollaborativeEditingHandler, + Inject, + SpreadsheetComponent +} from '@syncfusion/ej2-react-spreadsheet'; +import { CollaborationClient } from '@syncfusion/ej2-collaborator'; +import { SpreadsheetEditorAdapter } from './SpreadsheetEditorAdapter'; +import './App.css'; + +const serviceUrl: string = + 'https://appservice-267100-e9c8cxaab6a2dfeu.centralindia-01.azurewebsites.net/'; + +const currentUser: string = 'John'; + +function getRoomName(): string { + const currentUrl: URL = new URL(window.location.href); + + let roomName: string = ( + currentUrl.searchParams.get('id') || '' + ).trim(); + + if (!roomName) { + roomName = Math.random() + .toString(32) + .slice(2); + + currentUrl.searchParams.set( + 'id', + roomName + ); + + window.history.replaceState( + window.history.state, + '', + currentUrl.pathname + + currentUrl.search + + currentUrl.hash + ); + } + + return roomName; +} + +export default function App() { + const spreadsheetRef = + useRef(null); + + const adapterRef = + useRef(null); + + const clientRef = + useRef(null); + + const initializedRef = + useRef(false); + + const created = async (): Promise => { + const spreadsheet = spreadsheetRef.current; + + if (!spreadsheet || initializedRef.current) { + return; + } + + initializedRef.current = true; + + const roomName: string = getRoomName(); + + const adapter = new SpreadsheetEditorAdapter( + spreadsheet, + serviceUrl, + currentUser + ); + + try { + // Load the latest workbook and room version. + await adapter.loadFromServer( + 'Sample', + roomName + ); + + const client = new CollaborationClient( + adapter, + { + serviceUrl, + connectionType: 'signalr', + currentUser + } + ); + + adapterRef.current = adapter; + clientRef.current = client; + + // Connect to the real-time collaboration room. + await client.joinRoomAsync(roomName); + + console.log( + '[Collaborative Editing] Joined room', + roomName + ); + } catch (error) { + initializedRef.current = false; + + console.error( + '[Collaborative Editing] Failed to join the room.', + error + ); + } + }; + + const actionComplete = (args: unknown): void => { + adapterRef.current?.sendActionToServer(args); + }; + + return ( + + + + ); +} diff --git a/client/react/src/SpreadsheetEditorAdapter.ts b/client/react/src/SpreadsheetEditorAdapter.ts new file mode 100644 index 0000000..4452023 --- /dev/null +++ b/client/react/src/SpreadsheetEditorAdapter.ts @@ -0,0 +1,106 @@ + +import type { + ICollaborationActionData, + ICollaborationProvider +} from '@syncfusion/ej2-collaborator'; +import { SpreadsheetComponent } from '@syncfusion/ej2-react-spreadsheet'; + +interface ImportFileResponse { + sfdt: string; + version: number; +} + +export class SpreadsheetEditorAdapter + implements ICollaborationProvider { + + public currentRoomName: string = ''; + + public constructor( + private spreadsheet: SpreadsheetComponent, + private serviceUrl: string, + private currentUser: string + ) { + this.serviceUrl = serviceUrl.endsWith('/') + ? serviceUrl + : serviceUrl + '/'; + } + + public async loadFromServer( + fileName: string, + roomName: string + ): Promise { + const response: Response = await fetch( + this.serviceUrl + + 'api/CollaborativeEditing/ImportFile', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + fileName, + roomName + }) + } + ); + + if (!response.ok) { + throw new Error( + 'Failed to load the workbook.' + ); + } + + const data: ImportFileResponse = + JSON.parse(await response.text()); + + this.currentRoomName = roomName; + + // Initialize the room, server version, and API URL. + this.spreadsheet + .collaborativeEditingModule + .updateRoomInfo( + roomName, + data.version, + this.serviceUrl + + 'api/CollaborativeEditing/' + ); + + // Set the name displayed for the local participant. + this.spreadsheet + .collaborativeEditingModule + .setLocalUser(this.currentUser); + + // Open the latest synchronized workbook state. + this.spreadsheet.openFromJson({ + file: data.sfdt + }); + } + + public sendActionToServer( + action: unknown + ): void { + if (!action) { + return; + } + + this.spreadsheet + .collaborativeEditingModule + .sendActionToServer(action); + } + + public applyRemoteAction( + action: string, + data: ICollaborationActionData + ): void { + if (!data) { + return; + } + + this.spreadsheet + .collaborativeEditingModule + .applyRemoteAction( + action, + data.payload + ); + } +} diff --git a/client/react/src/main.tsx b/client/react/src/main.tsx new file mode 100644 index 0000000..71ffa42 --- /dev/null +++ b/client/react/src/main.tsx @@ -0,0 +1,11 @@ +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; +import App from './App'; + +createRoot( + document.getElementById('root')! +).render( + + + +); diff --git a/client/react/tsconfig.app.json b/client/react/tsconfig.app.json new file mode 100644 index 0000000..7af66d0 --- /dev/null +++ b/client/react/tsconfig.app.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": [ + "ES2022", + "DOM", + "DOM.Iterable" + ], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": [ + "src" + ] +} diff --git a/client/react/tsconfig.json b/client/react/tsconfig.json new file mode 100644 index 0000000..65f670c --- /dev/null +++ b/client/react/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.node.json" + } + ] +} \ No newline at end of file diff --git a/client/react/tsconfig.node.json b/client/react/tsconfig.node.json new file mode 100644 index 0000000..d1e6e2b --- /dev/null +++ b/client/react/tsconfig.node.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": [ + "ES2023" + ], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": [ + "vite.config.ts" + ] +} diff --git a/client/react/vite.config.ts b/client/react/vite.config.ts new file mode 100644 index 0000000..5d9373f --- /dev/null +++ b/client/react/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()] +}); \ No newline at end of file diff --git a/client/typescript/.gitignore b/client/typescript/.gitignore new file mode 100644 index 0000000..cc9689e --- /dev/null +++ b/client/typescript/.gitignore @@ -0,0 +1,6 @@ +node_modules +dist +.vscode/* +!.vscode/extensions.json +.DS_Store +*.local diff --git a/client/typescript/README.md b/client/typescript/README.md new file mode 100644 index 0000000..6738323 --- /dev/null +++ b/client/typescript/README.md @@ -0,0 +1,79 @@ +# TypeScript Spreadsheet Collaborative Editing + +This example demonstrates real-time collaborative editing in the Syncfusion Essential JS 2 TypeScript Spreadsheet. Multiple users can edit the same workbook, and supported actions are synchronized through the Collaboration Server. + +## Prerequisites + +- Node.js +- Redis Server +- ASP.NET Core Redis Collaboration Server, or access to the configured hosted Collaboration Server + +## Install dependencies + +```bash +npm install +``` + +## Configure the Collaboration Server + +The Collaboration Server URL is defined in `src/index.ts`. Update `serviceUrl` when a different server endpoint is used. + +## Run the application + +```bash +npm run dev +``` + +Open the URL displayed by Vite, normally: + +```text +http://localhost:5173/ +``` + +When the page opens without an `id` query parameter, the client generates a room ID and updates the URL. Open the complete URL in another browser tab or window to join the same collaboration room. + +Example: + +```text +http://localhost:5173/?id=sample-room +``` + +## Project structure + +```text +src/ +|-- index.ts +|-- spreadsheet-editor-adapter.ts +`-- style.css +``` + +## How it works + +1. `CollaborativeEditingHandler` is injected into the Spreadsheet. +2. The Spreadsheet starts with collaborative editing enabled. +3. The client obtains or generates a room ID from the URL. +4. The adapter imports the latest workbook and room version from the server. +5. `CollaborationClient` connects through SignalR and joins the room. +6. Local Spreadsheet actions are sent from `actionComplete`. +7. Remote actions are applied through `SpreadsheetEditorAdapter.applyRemoteAction`. + +## Build + +```bash +npm run build +``` + +## Important packages + +- `@syncfusion/ej2-spreadsheet` +- `@syncfusion/ej2-collaborator` +- `@microsoft/signalr` +- `@syncfusion/ej2-tailwind3-theme` + +## Troubleshooting + +If clients do not synchronize, verify that the Collaboration Server is reachable, Redis is running, all clients use the same room ID, and the browser console has no SignalR or CORS errors. + +## License + +Refer to the license file in the parent repository. diff --git a/client/typescript/index.html b/client/typescript/index.html new file mode 100644 index 0000000..accd0fa --- /dev/null +++ b/client/typescript/index.html @@ -0,0 +1,12 @@ + + + + + + TypeScript Spreadsheet Collaborative Editing + + +
+ + + diff --git a/client/typescript/package-lock.json b/client/typescript/package-lock.json new file mode 100644 index 0000000..8c42d8a --- /dev/null +++ b/client/typescript/package-lock.json @@ -0,0 +1,1678 @@ +{ + "name": "typescript-spreadsheet-collaborative-editing", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "typescript-spreadsheet-collaborative-editing", + "version": "1.0.0", + "dependencies": { + "@microsoft/signalr": "^9.0.0", + "@syncfusion/ej2-collaborator": "35.1.37", + "@syncfusion/ej2-spreadsheet": "35.1.37", + "@syncfusion/ej2-tailwind3-theme": "35.1.37" + }, + "devDependencies": { + "typescript": "~5.9.3", + "vite": "^7.1.9" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@microsoft/signalr": { + "version": "9.0.19", + "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-9.0.19.tgz", + "integrity": "sha512-hKDxt4nRXvkhhy+Etlhbg0UDQdhk8PsZKlQTnHyCn+bb+Q6gM8RCZLI43WsLH1IQCa7l/G8tX09em1F1LH/C1w==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "eventsource": "^2.0.2", + "fetch-cookie": "^2.0.3", + "node-fetch": "^2.6.7", + "ws": "^7.5.10" + } + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.63.5.tgz", + "integrity": "sha512-J25QJU+B78T4FhhBsNpLJyVWOi31mwtpcMwywHmOKH65Q9IWGA81gPj+dnwlhU8wktVriYE+tFAaQgrnJRzAZg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.63.5.tgz", + "integrity": "sha512-LDopB3zuZM5Ux9TT2luNEBJW/tYbGU2g1d+VpKk6I+gSKDb+/7sYE6M225gRQt4RbMX6MSwMsVR/phdjVUgRLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.63.5.tgz", + "integrity": "sha512-wlJEERGfeuHeBavCL2qVnNacOK43NDoZM4sjkeRPymd04OAE9T1zBqDJgmZ+CIsPTYKwdzpUC8vmOw84dwY4Tg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.63.5.tgz", + "integrity": "sha512-4nJJGg5jbo2wwPP4JP+LfEBA3bvP8rU9CLuhp7jWvq9sxEyhjQFTFdrqi+/dHEin/pd8jpT0vcehIpnZtmEdcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.63.5.tgz", + "integrity": "sha512-DrZbyCDF1hneuO6jRbvZ2D7+PIBM6yIwYnJpg2vIk58T+wuFpiaGZrfUr59lDWw45bg+IrpTGLPiNi/Fk4w3Cg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.63.5.tgz", + "integrity": "sha512-gqfUVMJMB3mehqywxp6hTBFfgtMQykZY19+cfiaYP0toIJLb/1DZRJHVkQQGP13W4TAwfZDWeg1qBcheTRioXQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.63.5.tgz", + "integrity": "sha512-CFmhpvAwzSaWMlN3VN7UtmoTihlZNzoP0juQib5TQRnYUyDV8dXeWOp29sobWAT6gXl/hQgAClLlEiYozQG3OQ==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.63.5.tgz", + "integrity": "sha512-Uc9H8eXCOayV6JLTH5bXKMId6qbhNHa818/BgYjm4jrlq3vZquC9cqyvHBw17xy5Mnj5f+I3gFK5JcEf3hSqrw==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.63.5.tgz", + "integrity": "sha512-VcPr/szv/1BFw112Kt//fxulXt/JPqzzidU84iW68L2DdjnOO8QFUv2zTSYBEPHD6movBD4z+bbr5y60GYM7Jw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.63.5.tgz", + "integrity": "sha512-BnxtJ5/91BrIHYIkGrmjz/lbMhqEHt1dPFqIxIFR+jPn0xVc/oUSCtIT089zfp5ufwGDlYz2UC+Fe1SRBpYFbQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.63.5.tgz", + "integrity": "sha512-LrYcHZwF+fAMNKHYTOQ5osWM4AZF7YF6D+XtsjDyEvljtt11twc+zHVXBLNEjxVSUnKYsOhvVz4Z213eW02COQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.63.5.tgz", + "integrity": "sha512-nj7QKQePAAUpCpJHtg0pR0W/b92A9NO17JS3BAQmHDn/yhmkir2p8llrKY9TOhleKIaSzy1JhxS3T9FVld6coA==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.63.5.tgz", + "integrity": "sha512-5ylkX6dWMeBKge9nTU+Rxfb+ZfaCIJ9lRqIFaK0eAMcWp7OJbYnLveLgXmm0VrvuLKb8qIK+mHyH0qu88RM+iA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.63.5.tgz", + "integrity": "sha512-oHK4ZHYFDKjZviK34I+NwgfbGxgI7ztrNxj2hPTSSNFgeq1a/lEd7dHV2fdGAuTH4Iym3RHJg+vAbWaWG4B7Zg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.63.5.tgz", + "integrity": "sha512-UcetmHZ6XOXuUByiKZyQmb55ZPr0LABr3Ec/HB9wKZn6CEAFWZkE+hsJErJ9hbPBC7nI0dKuELx7CoV6IM7TMg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.63.5.tgz", + "integrity": "sha512-C5CmDPQBtvjVo8cgQsBs+w6WB0JLkiixhgi6hVLV11hERWdn/p0XcPU2OUcZzac9BPOFq7SbaHFa8r3SWEysCQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.63.5.tgz", + "integrity": "sha512-lHVQHJFKsuuxLMi3MQO9XVL8Tje3JR82CzB+QDKC5NWBcsIWuwsn9uIM5e3lBhI+fF1/s63qnyYqsg65+8rV/w==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.63.5.tgz", + "integrity": "sha512-3W9bTFcQNJn71cSJVM9RKIiZOy8DO/XLDii8Uv/Pm6WKqDRj7JV3ZfuXIEfyuy5LXpIzAbB/1M4Ukp9GKNa7nA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.63.5.tgz", + "integrity": "sha512-VDC7rRJlee/scpki96GZ27Omf6yU87s1YXwVTpjE5841faVlDYYT565rgfmoR1U0sqL7z5ivQSDjcsF6VRXyBA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.63.5.tgz", + "integrity": "sha512-z86Ok2p4pTdv5xqCKZsTooO7yBEiaJR/HzU3Wx8RmWsPoLppnMKROhJusQob8B3IE1ghC343kUW9rC2r+Wf3ig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.63.5.tgz", + "integrity": "sha512-IzQmj+xXwQFGhMAMKMQVXkMwMZN3TqkJgAE0nSsqvVwWWciP4AIPMmWRqOQ2GfX7TUDZr+xqGFcBS36CRPGw0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.63.5.tgz", + "integrity": "sha512-F6qpTaPc9bwBH85kjy0/BLmLSW1uv7AoOXCoRIkg2arlgCYlWYcAbiMkvZuAcaWk9TpCRG//okznLAqLGshkMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.63.5.tgz", + "integrity": "sha512-igoDsTFhhwECBeGbUuLeIk7t8Y1apa+cs6mDWpx2EZ0ch7oEQgzHbFUXN9euoHekCAQzXdXApAGkV6jznS7tWw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.63.5.tgz", + "integrity": "sha512-U3teMeMbXFmaM5D+OTJpsOXd+wV/qftIeYF9kBKL4v73641qyJmoXFtA28DQLsnmlyayEsTe72xpLHrArq6vHw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.63.5.tgz", + "integrity": "sha512-ypfC34F3RKXvCXBglGqGMsUSMKlgwd1HX9AOAlx9RoZZ6GaI42YHVeKpzg3JG+wpBUJYTG+NNZhqbDWL8tBZkw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@syncfusion/ej2-base": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-base/-/ej2-base-35.1.37.tgz", + "integrity": "sha512-pg4WMFGbZJ9XoGr7ecBQ4+afWeVh1s0nckwqa1fFe1PK48Szg/gV5rEFXygFsHfratparBVAJogAd8WrWv3pYg==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-icons": "~35.1.37" + }, + "bin": { + "syncfusion-license": "bin/syncfusion-license.js" + } + }, + "node_modules/@syncfusion/ej2-buttons": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-buttons/-/ej2-buttons-35.1.37.tgz", + "integrity": "sha512-tLYpbTqfPPNBqVZ8SmwM9yw+gAkBRhD0Rcl+1YcrG/8z43tVqWJdemtOlOItV/GGEQXXhDbX7PKgJs9m3CDkrg==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-calculate": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-calculate/-/ej2-calculate-35.1.37.tgz", + "integrity": "sha512-q6Ogf+3vUcDZFOs7cdhFtXwrBmz555dSKnXNPe1QRdOhnZpOYIDYWcy0WlJ9E6zVk8SdvS3hMNKTmVP8DE1lxA==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-calendars": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-calendars/-/ej2-calendars-35.1.37.tgz", + "integrity": "sha512-KLYnPjinjjpHU4I4hZwJKWuMm8AYPWnnT7R/kVYQ0fMz4Vt1XrNCcOyByTvSINTDvb4sZeF6a5VTRNL6/i7Xgw==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-buttons": "~35.1.37", + "@syncfusion/ej2-inputs": "~35.1.37", + "@syncfusion/ej2-lists": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-charts": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-charts/-/ej2-charts-35.1.37.tgz", + "integrity": "sha512-q9ShJ4K7ozYRPqSpENay95eoe4ZBftHogveYTRsJTAKXCrh7tbjxJ9doeKBN+pcdqIBqcK0ecXDw4vPyxRvEtA==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-calendars": "~35.1.37", + "@syncfusion/ej2-data": "~35.1.37", + "@syncfusion/ej2-excel-export": "~35.1.37", + "@syncfusion/ej2-navigations": "~35.1.37", + "@syncfusion/ej2-pdf-export": "~35.1.37", + "@syncfusion/ej2-svg-base": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-collaborator": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-collaborator/-/ej2-collaborator-35.1.37.tgz", + "integrity": "sha512-Ff72o4M1yIw8VtjaiKyicHv7e5jr0jcL3Mak0yrvOCZoLyp4ucu5Zi5f+WHAy9qj4Tgu2WCuhzqRML8tx8G5gA==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-compression": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-compression/-/ej2-compression-35.1.37.tgz", + "integrity": "sha512-Lz+5N1iahYLtmyznJ9O+xTq34Mfc7PXFJna28h7PGJ7YNkZxJDLi1KijypJHj+LZfi8NAQsn7MRMnTFfbHxBmQ==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-file-utils": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-data": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-data/-/ej2-data-35.1.37.tgz", + "integrity": "sha512-rjHvWvwOYWCvWhptPe9ldenOKZXPXFer0v2UrbJhSfJ1oC9NxCm+HX1MrfY46SStOz93s3X8XorF2LgQlXRyRA==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-dropdowns": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-dropdowns/-/ej2-dropdowns-35.1.37.tgz", + "integrity": "sha512-StvzQPhuFZIQd53PAIWg7gsBiEKNMJuRueDgCNKTUoJo45fuHphShhb4RIwjnM1D6BJqQ1a/7oxeWQYxdaH/CQ==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-data": "~35.1.37", + "@syncfusion/ej2-inputs": "~35.1.37", + "@syncfusion/ej2-lists": "~35.1.37", + "@syncfusion/ej2-navigations": "~35.1.37", + "@syncfusion/ej2-notifications": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-excel-export": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-excel-export/-/ej2-excel-export-35.1.37.tgz", + "integrity": "sha512-oTjGCkiTpsx06EVbvwrwaTjORucMizuCb/AnfbjGoHVPGfZj74cchHQY+8rmY2uSRmz9nLQIGhc4Ip1JNcWDZg==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-compression": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-file-utils": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-file-utils/-/ej2-file-utils-35.1.37.tgz", + "integrity": "sha512-+Psm/DeB0b8DJeo63OU997bSSSL8Lj6s7tnY0CFUb1nXHmJ6pxxGLapf6MbBJYFSD+as1IWk2kFHkmWI1hu5Xg==", + "license": "SEE LICENSE IN license" + }, + "node_modules/@syncfusion/ej2-grids": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-grids/-/ej2-grids-35.1.37.tgz", + "integrity": "sha512-4t3o3VsUoYCes+gIVsYTyb2jbADfMMbGmGbJdeg9D4/Vl7sfvMdM7cWAxOX87oGwxhua29hQw7+8DLZ2Wm1Agg==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-buttons": "~35.1.37", + "@syncfusion/ej2-calendars": "~35.1.37", + "@syncfusion/ej2-compression": "~35.1.37", + "@syncfusion/ej2-data": "~35.1.37", + "@syncfusion/ej2-dropdowns": "~35.1.37", + "@syncfusion/ej2-excel-export": "~35.1.37", + "@syncfusion/ej2-file-utils": "~35.1.37", + "@syncfusion/ej2-inputs": "~35.1.37", + "@syncfusion/ej2-lists": "~35.1.37", + "@syncfusion/ej2-navigations": "~35.1.37", + "@syncfusion/ej2-notifications": "~35.1.37", + "@syncfusion/ej2-pdf-export": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37", + "@syncfusion/ej2-querybuilder": "~35.1.37", + "@syncfusion/ej2-splitbuttons": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-icons": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-icons/-/ej2-icons-35.1.37.tgz", + "integrity": "sha512-D7LC3O2OI2Ugc/DLShHvhoEPBEZCT9hj49PjV30CxfJ8ZyVR+EWl/GC3b1q1xMKLiB7ZhDrXBoZgq5mJaeVZuw==", + "license": "SEE LICENSE IN license" + }, + "node_modules/@syncfusion/ej2-inputs": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-inputs/-/ej2-inputs-35.1.37.tgz", + "integrity": "sha512-P4NQI/MQrfAqnpMNuRsxB0GMIXXZ5EIPPIt/oZnq1gAzGbDj7HM4yz4rg6xtiae8t2nMr0QI4cggL2dDKzpfHQ==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-buttons": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37", + "@syncfusion/ej2-splitbuttons": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-interactive-chat": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-interactive-chat/-/ej2-interactive-chat-35.1.37.tgz", + "integrity": "sha512-oq+h77v2DlbQBblBAfT25DKoLUMtBKiFxrlkgpDq2QqTLIhcD0XlrOXO5FKlUsLTMpmV71pZjpyNWyWc4rH+/g==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-dropdowns": "~35.1.37", + "@syncfusion/ej2-inputs": "~35.1.37", + "@syncfusion/ej2-layouts": "~35.1.37", + "@syncfusion/ej2-markdown-converter": "~35.1.37", + "@syncfusion/ej2-navigations": "~35.1.37", + "@syncfusion/ej2-notifications": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37", + "@syncfusion/ej2-splitbuttons": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-layouts": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-layouts/-/ej2-layouts-35.1.37.tgz", + "integrity": "sha512-5yj54DPYAKLjuIA+pO3IaZryGWbqAfXRZZuyOb35cjOFHoDDeAoQ9x0ocigxUYFv/IOx/6JW3M79Fb3hx7XA8g==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-lists": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-lists/-/ej2-lists-35.1.37.tgz", + "integrity": "sha512-GA5cnNXA+Kpme2nDAxld7x88T1YnoMDvHidTk2CJj/Dp3mwvB2/FScaGxYjidES1Hev0XWvJtgnGPdhI95gE2Q==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-buttons": "~35.1.37", + "@syncfusion/ej2-data": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-markdown-converter": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-markdown-converter/-/ej2-markdown-converter-35.1.37.tgz", + "integrity": "sha512-fBtN3+1ACdXIYbzAX35gDcOTtR5VCdjW2QSWaLpO3jhh+NntOrhfM82ntxI+TOdyZYOvtNxt/pQjIp2K/UOGBA==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-navigations": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-navigations/-/ej2-navigations-35.1.37.tgz", + "integrity": "sha512-jqpVXZimfqfIPzCf9I7KPB47hVdiouYDnmEHIpayekQlSdMq2qZQJy59sqb8genYL4OR/KnEFJlcIp1mdhJ8Kw==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-buttons": "~35.1.37", + "@syncfusion/ej2-data": "~35.1.37", + "@syncfusion/ej2-inputs": "~35.1.37", + "@syncfusion/ej2-lists": "~35.1.37", + "@syncfusion/ej2-notifications": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-notifications": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-notifications/-/ej2-notifications-35.1.37.tgz", + "integrity": "sha512-UyjQ2Ykx8N1YrikYxrMaK9F7x/u4Ea4ZdCO8rL07binfF+lDEFlPpMoLbiQYatwb8gN++d5UbcyQXs/sYLIYfg==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-buttons": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-pdf-export": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-pdf-export/-/ej2-pdf-export-35.1.37.tgz", + "integrity": "sha512-9+2GJBe0vjs0CuIBgQQd7GcQ2CaxCh//OqNlnbGvPO4dfagEj0TUoKpbhIK9Qs5+l1KHvpSgPhQ80LuZBfyHhw==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-compression": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-popups": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-popups/-/ej2-popups-35.1.37.tgz", + "integrity": "sha512-HC3x/sR07YDDc/eS/iZrN0SyJkuAXDS1uRABeN6UdPdkp2o7IOkSOCAyAURMY/dHqpCDblhsnE0LXZ6HwlcQaQ==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-buttons": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-querybuilder": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-querybuilder/-/ej2-querybuilder-35.1.37.tgz", + "integrity": "sha512-h2xUbOt+I88ICtWRhcMrmizfX4fXU9ZfSc2cR/Umn5vSoMJE52AEAQ9iamRiMTJUFAwOyINpdfabr1pO7xngKg==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-buttons": "~35.1.37", + "@syncfusion/ej2-calendars": "~35.1.37", + "@syncfusion/ej2-dropdowns": "~35.1.37", + "@syncfusion/ej2-inputs": "~35.1.37", + "@syncfusion/ej2-splitbuttons": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-splitbuttons": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-splitbuttons/-/ej2-splitbuttons-35.1.37.tgz", + "integrity": "sha512-whjKUf7p9grTtDxssx4s2u9gYDysiRHBn658dj6oRMKoYAECdaw5H/WEIcqKoxA6B1hJyUHZ8GE1SbWdV7eSVw==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-spreadsheet": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-spreadsheet/-/ej2-spreadsheet-35.1.37.tgz", + "integrity": "sha512-TEM28i5E17uFG37HpYLaRhpjiyq/k4KxQG6MJMTn3JroZtM2+BUvki6l847xhCdPt1Jrvg8slc0uKI28Cox3XA==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-calculate": "~35.1.37", + "@syncfusion/ej2-charts": "~35.1.37", + "@syncfusion/ej2-dropdowns": "~35.1.37", + "@syncfusion/ej2-grids": "~35.1.37", + "@syncfusion/ej2-interactive-chat": "~35.1.37", + "@syncfusion/ej2-navigations": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-svg-base": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-svg-base/-/ej2-svg-base-35.1.37.tgz", + "integrity": "sha512-jgTjelQSmDHETQfXaecRL92tw/i63ijnACZEwp97gDl+bbY8Nc/PjTvaHNjECjuOL2Nt83q4z77OnGjE2zmNJQ==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-tailwind3-theme": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-tailwind3-theme/-/ej2-tailwind3-theme-35.1.37.tgz", + "integrity": "sha512-1Qujjxkeo4pH58CcBHytkqwTuZZRlFeoEfdzyfkvZGjtcg9dH2sOMYVwz6GVs4dRrtm/KJkqeBXMToCMR6bT2g==", + "license": "SEE LICENSE IN license" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fetch-cookie": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-2.2.0.tgz", + "integrity": "sha512-h9AgfjURuCgA2+2ISl8GbavpUdR+WGAM2McW/ovn4tVccegp8ZqCKWSBR8uRdM8dDNlx5WdKRWxBYUwteLDCNQ==", + "license": "Unlicense", + "dependencies": { + "set-cookie-parser": "^2.4.8", + "tough-cookie": "^4.0.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.19", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", + "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.28", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", + "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.18", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "license": "MIT" + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.63.5.tgz", + "integrity": "sha512-KRWwmNLlPw5M7HcdYfm15oBv9n9LPtjzpzCIxS/phwqvPyxHSoKX6Y2YU3pxSPfy0CLquVgsx/j/hBi6OvH1Nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.63.5", + "@rollup/rollup-android-arm64": "4.63.5", + "@rollup/rollup-darwin-arm64": "4.63.5", + "@rollup/rollup-darwin-x64": "4.63.5", + "@rollup/rollup-freebsd-arm64": "4.63.5", + "@rollup/rollup-freebsd-x64": "4.63.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.63.5", + "@rollup/rollup-linux-arm-musleabihf": "4.63.5", + "@rollup/rollup-linux-arm64-gnu": "4.63.5", + "@rollup/rollup-linux-arm64-musl": "4.63.5", + "@rollup/rollup-linux-loong64-gnu": "4.63.5", + "@rollup/rollup-linux-loong64-musl": "4.63.5", + "@rollup/rollup-linux-ppc64-gnu": "4.63.5", + "@rollup/rollup-linux-ppc64-musl": "4.63.5", + "@rollup/rollup-linux-riscv64-gnu": "4.63.5", + "@rollup/rollup-linux-riscv64-musl": "4.63.5", + "@rollup/rollup-linux-s390x-gnu": "4.63.5", + "@rollup/rollup-linux-x64-gnu": "4.63.5", + "@rollup/rollup-linux-x64-musl": "4.63.5", + "@rollup/rollup-openbsd-x64": "4.63.5", + "@rollup/rollup-openharmony-arm64": "4.63.5", + "@rollup/rollup-win32-arm64-msvc": "4.63.5", + "@rollup/rollup-win32-ia32-msvc": "4.63.5", + "@rollup/rollup-win32-x64-gnu": "4.63.5", + "@rollup/rollup-win32-x64-msvc": "4.63.5", + "fsevents": "~2.3.2" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/vite": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", + "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0 || ^0.28.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/ws": { + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", + "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/client/typescript/package.json b/client/typescript/package.json new file mode 100644 index 0000000..2eb6b1a --- /dev/null +++ b/client/typescript/package.json @@ -0,0 +1,21 @@ +{ + "name": "typescript-spreadsheet-collaborative-editing", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "@microsoft/signalr": "^9.0.0", + "@syncfusion/ej2-collaborator": "35.1.37", + "@syncfusion/ej2-spreadsheet": "35.1.37", + "@syncfusion/ej2-tailwind3-theme": "35.1.37" + }, + "devDependencies": { + "typescript": "~5.9.3", + "vite": "^7.1.9" + } +} diff --git a/client/typescript/src/index.ts b/client/typescript/src/index.ts new file mode 100644 index 0000000..84b604d --- /dev/null +++ b/client/typescript/src/index.ts @@ -0,0 +1,89 @@ +import { + CollaborativeEditingHandler, + Spreadsheet +} from '@syncfusion/ej2-spreadsheet'; +import { CollaborationClient } from '@syncfusion/ej2-collaborator'; +import { SpreadsheetEditorAdapter } from './spreadsheet-editor-adapter'; +import './style.css'; + +const serviceUrl: string = + 'https://appservice-267100-e9c8cxaab6a2dfeu.centralindia-01.azurewebsites.net/'; +const currentUser: string = 'John'; + +Spreadsheet.Inject(CollaborativeEditingHandler); + +function getRoomName(): string { + const currentUrl: URL = new URL(window.location.href); + let roomName: string = ( + currentUrl.searchParams.get('id') || '' + ).trim(); + + if (!roomName) { + roomName = Math.random().toString(32).slice(2); + currentUrl.searchParams.set('id', roomName); + window.history.replaceState( + window.history.state, + '', + currentUrl.pathname + currentUrl.search + currentUrl.hash + ); + } + + return roomName; +} + +let adapter: SpreadsheetEditorAdapter | null = null; +let client: CollaborationClient | null = null; +let initialized: boolean = false; + +const spreadsheet: Spreadsheet = new Spreadsheet({ + height: '550px', + enableCollaborativeEditing: true, + created: async (): Promise => { + if (initialized) { + return; + } + + initialized = true; + const roomName: string = getRoomName(); + const spreadsheetAdapter = new SpreadsheetEditorAdapter( + spreadsheet, + serviceUrl, + currentUser + ); + + try { + await spreadsheetAdapter.loadFromServer('Sample', roomName); + + const collaborationClient = new CollaborationClient( + spreadsheetAdapter, + { + serviceUrl, + connectionType: 'signalr', + currentUser + } + ); + + adapter = spreadsheetAdapter; + client = collaborationClient; + await collaborationClient.joinRoomAsync(roomName); + + console.log( + '[Collaborative Editing] Joined room', + roomName + ); + } catch (error) { + initialized = false; + console.error( + '[Collaborative Editing] Failed to join the room.', + error + ); + } + }, + actionComplete: (args: unknown): void => { + adapter?.sendActionToServer(args); + } +}); + +spreadsheet.appendTo('#spreadsheet'); + +void client; diff --git a/client/typescript/src/spreadsheet-editor-adapter.ts b/client/typescript/src/spreadsheet-editor-adapter.ts new file mode 100644 index 0000000..16b703a --- /dev/null +++ b/client/typescript/src/spreadsheet-editor-adapter.ts @@ -0,0 +1,83 @@ +import type { + ICollaborationActionData, + ICollaborationProvider +} from '@syncfusion/ej2-collaborator'; +import type { Spreadsheet } from '@syncfusion/ej2-spreadsheet'; + +interface ImportFileResponse { + sfdt: string; + version: number; +} + +export class SpreadsheetEditorAdapter implements ICollaborationProvider { + public currentRoomName: string = ''; + + public constructor( + private spreadsheet: Spreadsheet, + private serviceUrl: string, + private currentUser: string + ) { + this.serviceUrl = serviceUrl.endsWith('/') + ? serviceUrl + : serviceUrl + '/'; + } + + public async loadFromServer( + fileName: string, + roomName: string + ): Promise { + const response: Response = await fetch( + this.serviceUrl + 'api/CollaborativeEditing/ImportFile', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ fileName, roomName }) + } + ); + + if (!response.ok) { + throw new Error('Failed to load the workbook.'); + } + + const data: ImportFileResponse = JSON.parse( + await response.text() + ); + + this.currentRoomName = roomName; + this.spreadsheet.collaborativeEditingModule.updateRoomInfo( + roomName, + data.version, + this.serviceUrl + 'api/CollaborativeEditing/' + ); + this.spreadsheet.collaborativeEditingModule.setLocalUser( + this.currentUser + ); + this.spreadsheet.openFromJson({ file: data.sfdt }); + } + + public sendActionToServer(action: unknown): void { + if (!action) { + return; + } + + this.spreadsheet.collaborativeEditingModule.sendActionToServer( + action + ); + } + + public applyRemoteAction( + action: string, + data: ICollaborationActionData + ): void { + if (!data) { + return; + } + + this.spreadsheet.collaborativeEditingModule.applyRemoteAction( + action, + data.payload + ); + } +} diff --git a/client/typescript/src/style.css b/client/typescript/src/style.css new file mode 100644 index 0000000..8a9a433 --- /dev/null +++ b/client/typescript/src/style.css @@ -0,0 +1,11 @@ +@import '@syncfusion/ej2-tailwind3-theme/styles/tailwind3.css'; + +html, +body { + height: 100%; + margin: 0; +} + +#spreadsheet { + width: 100%; +} diff --git a/client/typescript/tsconfig.json b/client/typescript/tsconfig.json new file mode 100644 index 0000000..4f2e02c --- /dev/null +++ b/client/typescript/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "strict": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/client/vue/.gitignore b/client/vue/.gitignore new file mode 100644 index 0000000..cc9689e --- /dev/null +++ b/client/vue/.gitignore @@ -0,0 +1,6 @@ +node_modules +dist +.vscode/* +!.vscode/extensions.json +.DS_Store +*.local diff --git a/client/vue/README.md b/client/vue/README.md new file mode 100644 index 0000000..a6e56ad --- /dev/null +++ b/client/vue/README.md @@ -0,0 +1,78 @@ +# Vue Spreadsheet Collaborative Editing + +This example demonstrates real-time collaborative editing in the Syncfusion Vue Spreadsheet. Multiple users can edit the same workbook, and supported actions are synchronized through the Collaboration Server. + +## Prerequisites + +- Node.js +- Redis Server +- ASP.NET Core Redis Collaboration Server, or access to the configured hosted Collaboration Server + +## Install dependencies + +```bash +npm install +``` + +## Configure the Collaboration Server + +The Collaboration Server URL is defined in `src/App.vue`. Update `serviceUrl` when a different server endpoint is used. + +## Run the application + +```bash +npm run dev +``` + +Open the URL displayed by Vite, normally `http://localhost:5173/`. + +When the page opens without an `id` query parameter, the client generates a room ID and updates the URL. Open the complete URL in another browser tab or window to join the same collaboration room. + +Example: + +```text +http://localhost:5173/?id=sample-room +``` + +## Project structure + +```text +src/ +|-- App.vue +|-- SpreadsheetEditorAdapter.ts +|-- main.ts +|-- style.css +`-- vite-env.d.ts +``` + +## How it works + +1. The Vue Spreadsheet starts with collaborative editing enabled. +2. `CollaborativeEditingHandler` is provided to the Spreadsheet. +3. The client obtains or generates a room ID from the URL. +4. The adapter imports the latest workbook and room version from the server. +5. `CollaborationClient` connects through SignalR and joins the room. +6. Local Spreadsheet actions are sent from `actionComplete`. +7. Remote actions are applied through `SpreadsheetEditorAdapter.applyRemoteAction`. + +## Build + +```bash +npm run build +``` + +## Important packages + +- `@syncfusion/ej2-vue-spreadsheet` +- `@syncfusion/ej2-spreadsheet` +- `@syncfusion/ej2-collaborator` +- `@microsoft/signalr` +- `@syncfusion/ej2-tailwind3-theme` + +## Troubleshooting + +If clients do not synchronize, verify that the Collaboration Server is reachable, Redis is running, all clients use the same room ID, and the browser console has no SignalR or CORS errors. + +## License + +Refer to the license file in the parent repository. diff --git a/client/vue/index.html b/client/vue/index.html new file mode 100644 index 0000000..e074791 --- /dev/null +++ b/client/vue/index.html @@ -0,0 +1,12 @@ + + + + + + Vue Spreadsheet Collaborative Editing + + +
+ + + diff --git a/client/vue/package-lock.json b/client/vue/package-lock.json new file mode 100644 index 0000000..a438a9b --- /dev/null +++ b/client/vue/package-lock.json @@ -0,0 +1,2054 @@ +{ + "name": "vue-spreadsheet-collaborative-editing", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "vue-spreadsheet-collaborative-editing", + "version": "1.0.0", + "dependencies": { + "@microsoft/signalr": "^9.0.0", + "@syncfusion/ej2-collaborator": "35.1.37", + "@syncfusion/ej2-spreadsheet": "35.1.37", + "@syncfusion/ej2-tailwind3-theme": "35.1.37", + "@syncfusion/ej2-vue-spreadsheet": "35.1.37", + "vue": "^3.5.22" + }, + "devDependencies": { + "@types/node": "^24.7.0", + "@vitejs/plugin-vue": "^6.0.1", + "@vue/tsconfig": "^0.8.1", + "typescript": "~5.9.3", + "vite": "^7.1.9", + "vue-tsc": "^3.1.1" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", + "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "license": "MIT" + }, + "node_modules/@microsoft/signalr": { + "version": "9.0.19", + "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-9.0.19.tgz", + "integrity": "sha512-hKDxt4nRXvkhhy+Etlhbg0UDQdhk8PsZKlQTnHyCn+bb+Q6gM8RCZLI43WsLH1IQCa7l/G8tX09em1F1LH/C1w==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "eventsource": "^2.0.2", + "fetch-cookie": "^2.0.3", + "node-fetch": "^2.6.7", + "ws": "^7.5.10" + } + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.63.5.tgz", + "integrity": "sha512-J25QJU+B78T4FhhBsNpLJyVWOi31mwtpcMwywHmOKH65Q9IWGA81gPj+dnwlhU8wktVriYE+tFAaQgrnJRzAZg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.63.5.tgz", + "integrity": "sha512-LDopB3zuZM5Ux9TT2luNEBJW/tYbGU2g1d+VpKk6I+gSKDb+/7sYE6M225gRQt4RbMX6MSwMsVR/phdjVUgRLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.63.5.tgz", + "integrity": "sha512-wlJEERGfeuHeBavCL2qVnNacOK43NDoZM4sjkeRPymd04OAE9T1zBqDJgmZ+CIsPTYKwdzpUC8vmOw84dwY4Tg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.63.5.tgz", + "integrity": "sha512-4nJJGg5jbo2wwPP4JP+LfEBA3bvP8rU9CLuhp7jWvq9sxEyhjQFTFdrqi+/dHEin/pd8jpT0vcehIpnZtmEdcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.63.5.tgz", + "integrity": "sha512-DrZbyCDF1hneuO6jRbvZ2D7+PIBM6yIwYnJpg2vIk58T+wuFpiaGZrfUr59lDWw45bg+IrpTGLPiNi/Fk4w3Cg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.63.5.tgz", + "integrity": "sha512-gqfUVMJMB3mehqywxp6hTBFfgtMQykZY19+cfiaYP0toIJLb/1DZRJHVkQQGP13W4TAwfZDWeg1qBcheTRioXQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.63.5.tgz", + "integrity": "sha512-CFmhpvAwzSaWMlN3VN7UtmoTihlZNzoP0juQib5TQRnYUyDV8dXeWOp29sobWAT6gXl/hQgAClLlEiYozQG3OQ==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.63.5.tgz", + "integrity": "sha512-Uc9H8eXCOayV6JLTH5bXKMId6qbhNHa818/BgYjm4jrlq3vZquC9cqyvHBw17xy5Mnj5f+I3gFK5JcEf3hSqrw==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.63.5.tgz", + "integrity": "sha512-VcPr/szv/1BFw112Kt//fxulXt/JPqzzidU84iW68L2DdjnOO8QFUv2zTSYBEPHD6movBD4z+bbr5y60GYM7Jw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.63.5.tgz", + "integrity": "sha512-BnxtJ5/91BrIHYIkGrmjz/lbMhqEHt1dPFqIxIFR+jPn0xVc/oUSCtIT089zfp5ufwGDlYz2UC+Fe1SRBpYFbQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.63.5.tgz", + "integrity": "sha512-LrYcHZwF+fAMNKHYTOQ5osWM4AZF7YF6D+XtsjDyEvljtt11twc+zHVXBLNEjxVSUnKYsOhvVz4Z213eW02COQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.63.5.tgz", + "integrity": "sha512-nj7QKQePAAUpCpJHtg0pR0W/b92A9NO17JS3BAQmHDn/yhmkir2p8llrKY9TOhleKIaSzy1JhxS3T9FVld6coA==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.63.5.tgz", + "integrity": "sha512-5ylkX6dWMeBKge9nTU+Rxfb+ZfaCIJ9lRqIFaK0eAMcWp7OJbYnLveLgXmm0VrvuLKb8qIK+mHyH0qu88RM+iA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.63.5.tgz", + "integrity": "sha512-oHK4ZHYFDKjZviK34I+NwgfbGxgI7ztrNxj2hPTSSNFgeq1a/lEd7dHV2fdGAuTH4Iym3RHJg+vAbWaWG4B7Zg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.63.5.tgz", + "integrity": "sha512-UcetmHZ6XOXuUByiKZyQmb55ZPr0LABr3Ec/HB9wKZn6CEAFWZkE+hsJErJ9hbPBC7nI0dKuELx7CoV6IM7TMg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.63.5.tgz", + "integrity": "sha512-C5CmDPQBtvjVo8cgQsBs+w6WB0JLkiixhgi6hVLV11hERWdn/p0XcPU2OUcZzac9BPOFq7SbaHFa8r3SWEysCQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.63.5.tgz", + "integrity": "sha512-lHVQHJFKsuuxLMi3MQO9XVL8Tje3JR82CzB+QDKC5NWBcsIWuwsn9uIM5e3lBhI+fF1/s63qnyYqsg65+8rV/w==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.63.5.tgz", + "integrity": "sha512-3W9bTFcQNJn71cSJVM9RKIiZOy8DO/XLDii8Uv/Pm6WKqDRj7JV3ZfuXIEfyuy5LXpIzAbB/1M4Ukp9GKNa7nA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.63.5.tgz", + "integrity": "sha512-VDC7rRJlee/scpki96GZ27Omf6yU87s1YXwVTpjE5841faVlDYYT565rgfmoR1U0sqL7z5ivQSDjcsF6VRXyBA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.63.5.tgz", + "integrity": "sha512-z86Ok2p4pTdv5xqCKZsTooO7yBEiaJR/HzU3Wx8RmWsPoLppnMKROhJusQob8B3IE1ghC343kUW9rC2r+Wf3ig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.63.5.tgz", + "integrity": "sha512-IzQmj+xXwQFGhMAMKMQVXkMwMZN3TqkJgAE0nSsqvVwWWciP4AIPMmWRqOQ2GfX7TUDZr+xqGFcBS36CRPGw0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.63.5.tgz", + "integrity": "sha512-F6qpTaPc9bwBH85kjy0/BLmLSW1uv7AoOXCoRIkg2arlgCYlWYcAbiMkvZuAcaWk9TpCRG//okznLAqLGshkMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.63.5.tgz", + "integrity": "sha512-igoDsTFhhwECBeGbUuLeIk7t8Y1apa+cs6mDWpx2EZ0ch7oEQgzHbFUXN9euoHekCAQzXdXApAGkV6jznS7tWw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.63.5.tgz", + "integrity": "sha512-U3teMeMbXFmaM5D+OTJpsOXd+wV/qftIeYF9kBKL4v73641qyJmoXFtA28DQLsnmlyayEsTe72xpLHrArq6vHw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.63.5.tgz", + "integrity": "sha512-ypfC34F3RKXvCXBglGqGMsUSMKlgwd1HX9AOAlx9RoZZ6GaI42YHVeKpzg3JG+wpBUJYTG+NNZhqbDWL8tBZkw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@syncfusion/ej2-base": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-base/-/ej2-base-35.1.37.tgz", + "integrity": "sha512-pg4WMFGbZJ9XoGr7ecBQ4+afWeVh1s0nckwqa1fFe1PK48Szg/gV5rEFXygFsHfratparBVAJogAd8WrWv3pYg==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-icons": "~35.1.37" + }, + "bin": { + "syncfusion-license": "bin/syncfusion-license.js" + } + }, + "node_modules/@syncfusion/ej2-buttons": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-buttons/-/ej2-buttons-35.1.37.tgz", + "integrity": "sha512-tLYpbTqfPPNBqVZ8SmwM9yw+gAkBRhD0Rcl+1YcrG/8z43tVqWJdemtOlOItV/GGEQXXhDbX7PKgJs9m3CDkrg==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-calculate": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-calculate/-/ej2-calculate-35.1.37.tgz", + "integrity": "sha512-q6Ogf+3vUcDZFOs7cdhFtXwrBmz555dSKnXNPe1QRdOhnZpOYIDYWcy0WlJ9E6zVk8SdvS3hMNKTmVP8DE1lxA==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-calendars": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-calendars/-/ej2-calendars-35.1.37.tgz", + "integrity": "sha512-KLYnPjinjjpHU4I4hZwJKWuMm8AYPWnnT7R/kVYQ0fMz4Vt1XrNCcOyByTvSINTDvb4sZeF6a5VTRNL6/i7Xgw==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-buttons": "~35.1.37", + "@syncfusion/ej2-inputs": "~35.1.37", + "@syncfusion/ej2-lists": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-charts": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-charts/-/ej2-charts-35.1.37.tgz", + "integrity": "sha512-q9ShJ4K7ozYRPqSpENay95eoe4ZBftHogveYTRsJTAKXCrh7tbjxJ9doeKBN+pcdqIBqcK0ecXDw4vPyxRvEtA==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-calendars": "~35.1.37", + "@syncfusion/ej2-data": "~35.1.37", + "@syncfusion/ej2-excel-export": "~35.1.37", + "@syncfusion/ej2-navigations": "~35.1.37", + "@syncfusion/ej2-pdf-export": "~35.1.37", + "@syncfusion/ej2-svg-base": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-collaborator": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-collaborator/-/ej2-collaborator-35.1.37.tgz", + "integrity": "sha512-Ff72o4M1yIw8VtjaiKyicHv7e5jr0jcL3Mak0yrvOCZoLyp4ucu5Zi5f+WHAy9qj4Tgu2WCuhzqRML8tx8G5gA==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-compression": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-compression/-/ej2-compression-35.1.37.tgz", + "integrity": "sha512-Lz+5N1iahYLtmyznJ9O+xTq34Mfc7PXFJna28h7PGJ7YNkZxJDLi1KijypJHj+LZfi8NAQsn7MRMnTFfbHxBmQ==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-file-utils": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-data": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-data/-/ej2-data-35.1.37.tgz", + "integrity": "sha512-rjHvWvwOYWCvWhptPe9ldenOKZXPXFer0v2UrbJhSfJ1oC9NxCm+HX1MrfY46SStOz93s3X8XorF2LgQlXRyRA==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-dropdowns": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-dropdowns/-/ej2-dropdowns-35.1.37.tgz", + "integrity": "sha512-StvzQPhuFZIQd53PAIWg7gsBiEKNMJuRueDgCNKTUoJo45fuHphShhb4RIwjnM1D6BJqQ1a/7oxeWQYxdaH/CQ==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-data": "~35.1.37", + "@syncfusion/ej2-inputs": "~35.1.37", + "@syncfusion/ej2-lists": "~35.1.37", + "@syncfusion/ej2-navigations": "~35.1.37", + "@syncfusion/ej2-notifications": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-excel-export": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-excel-export/-/ej2-excel-export-35.1.37.tgz", + "integrity": "sha512-oTjGCkiTpsx06EVbvwrwaTjORucMizuCb/AnfbjGoHVPGfZj74cchHQY+8rmY2uSRmz9nLQIGhc4Ip1JNcWDZg==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-compression": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-file-utils": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-file-utils/-/ej2-file-utils-35.1.37.tgz", + "integrity": "sha512-+Psm/DeB0b8DJeo63OU997bSSSL8Lj6s7tnY0CFUb1nXHmJ6pxxGLapf6MbBJYFSD+as1IWk2kFHkmWI1hu5Xg==", + "license": "SEE LICENSE IN license" + }, + "node_modules/@syncfusion/ej2-grids": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-grids/-/ej2-grids-35.1.37.tgz", + "integrity": "sha512-4t3o3VsUoYCes+gIVsYTyb2jbADfMMbGmGbJdeg9D4/Vl7sfvMdM7cWAxOX87oGwxhua29hQw7+8DLZ2Wm1Agg==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-buttons": "~35.1.37", + "@syncfusion/ej2-calendars": "~35.1.37", + "@syncfusion/ej2-compression": "~35.1.37", + "@syncfusion/ej2-data": "~35.1.37", + "@syncfusion/ej2-dropdowns": "~35.1.37", + "@syncfusion/ej2-excel-export": "~35.1.37", + "@syncfusion/ej2-file-utils": "~35.1.37", + "@syncfusion/ej2-inputs": "~35.1.37", + "@syncfusion/ej2-lists": "~35.1.37", + "@syncfusion/ej2-navigations": "~35.1.37", + "@syncfusion/ej2-notifications": "~35.1.37", + "@syncfusion/ej2-pdf-export": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37", + "@syncfusion/ej2-querybuilder": "~35.1.37", + "@syncfusion/ej2-splitbuttons": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-icons": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-icons/-/ej2-icons-35.1.37.tgz", + "integrity": "sha512-D7LC3O2OI2Ugc/DLShHvhoEPBEZCT9hj49PjV30CxfJ8ZyVR+EWl/GC3b1q1xMKLiB7ZhDrXBoZgq5mJaeVZuw==", + "license": "SEE LICENSE IN license" + }, + "node_modules/@syncfusion/ej2-inputs": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-inputs/-/ej2-inputs-35.1.37.tgz", + "integrity": "sha512-P4NQI/MQrfAqnpMNuRsxB0GMIXXZ5EIPPIt/oZnq1gAzGbDj7HM4yz4rg6xtiae8t2nMr0QI4cggL2dDKzpfHQ==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-buttons": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37", + "@syncfusion/ej2-splitbuttons": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-interactive-chat": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-interactive-chat/-/ej2-interactive-chat-35.1.37.tgz", + "integrity": "sha512-oq+h77v2DlbQBblBAfT25DKoLUMtBKiFxrlkgpDq2QqTLIhcD0XlrOXO5FKlUsLTMpmV71pZjpyNWyWc4rH+/g==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-dropdowns": "~35.1.37", + "@syncfusion/ej2-inputs": "~35.1.37", + "@syncfusion/ej2-layouts": "~35.1.37", + "@syncfusion/ej2-markdown-converter": "~35.1.37", + "@syncfusion/ej2-navigations": "~35.1.37", + "@syncfusion/ej2-notifications": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37", + "@syncfusion/ej2-splitbuttons": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-layouts": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-layouts/-/ej2-layouts-35.1.37.tgz", + "integrity": "sha512-5yj54DPYAKLjuIA+pO3IaZryGWbqAfXRZZuyOb35cjOFHoDDeAoQ9x0ocigxUYFv/IOx/6JW3M79Fb3hx7XA8g==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-lists": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-lists/-/ej2-lists-35.1.37.tgz", + "integrity": "sha512-GA5cnNXA+Kpme2nDAxld7x88T1YnoMDvHidTk2CJj/Dp3mwvB2/FScaGxYjidES1Hev0XWvJtgnGPdhI95gE2Q==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-buttons": "~35.1.37", + "@syncfusion/ej2-data": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-markdown-converter": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-markdown-converter/-/ej2-markdown-converter-35.1.37.tgz", + "integrity": "sha512-fBtN3+1ACdXIYbzAX35gDcOTtR5VCdjW2QSWaLpO3jhh+NntOrhfM82ntxI+TOdyZYOvtNxt/pQjIp2K/UOGBA==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-navigations": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-navigations/-/ej2-navigations-35.1.37.tgz", + "integrity": "sha512-jqpVXZimfqfIPzCf9I7KPB47hVdiouYDnmEHIpayekQlSdMq2qZQJy59sqb8genYL4OR/KnEFJlcIp1mdhJ8Kw==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-buttons": "~35.1.37", + "@syncfusion/ej2-data": "~35.1.37", + "@syncfusion/ej2-inputs": "~35.1.37", + "@syncfusion/ej2-lists": "~35.1.37", + "@syncfusion/ej2-notifications": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-notifications": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-notifications/-/ej2-notifications-35.1.37.tgz", + "integrity": "sha512-UyjQ2Ykx8N1YrikYxrMaK9F7x/u4Ea4ZdCO8rL07binfF+lDEFlPpMoLbiQYatwb8gN++d5UbcyQXs/sYLIYfg==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-buttons": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-pdf-export": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-pdf-export/-/ej2-pdf-export-35.1.37.tgz", + "integrity": "sha512-9+2GJBe0vjs0CuIBgQQd7GcQ2CaxCh//OqNlnbGvPO4dfagEj0TUoKpbhIK9Qs5+l1KHvpSgPhQ80LuZBfyHhw==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-compression": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-popups": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-popups/-/ej2-popups-35.1.37.tgz", + "integrity": "sha512-HC3x/sR07YDDc/eS/iZrN0SyJkuAXDS1uRABeN6UdPdkp2o7IOkSOCAyAURMY/dHqpCDblhsnE0LXZ6HwlcQaQ==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-buttons": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-querybuilder": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-querybuilder/-/ej2-querybuilder-35.1.37.tgz", + "integrity": "sha512-h2xUbOt+I88ICtWRhcMrmizfX4fXU9ZfSc2cR/Umn5vSoMJE52AEAQ9iamRiMTJUFAwOyINpdfabr1pO7xngKg==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-buttons": "~35.1.37", + "@syncfusion/ej2-calendars": "~35.1.37", + "@syncfusion/ej2-dropdowns": "~35.1.37", + "@syncfusion/ej2-inputs": "~35.1.37", + "@syncfusion/ej2-splitbuttons": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-splitbuttons": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-splitbuttons/-/ej2-splitbuttons-35.1.37.tgz", + "integrity": "sha512-whjKUf7p9grTtDxssx4s2u9gYDysiRHBn658dj6oRMKoYAECdaw5H/WEIcqKoxA6B1hJyUHZ8GE1SbWdV7eSVw==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-popups": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-spreadsheet": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-spreadsheet/-/ej2-spreadsheet-35.1.37.tgz", + "integrity": "sha512-TEM28i5E17uFG37HpYLaRhpjiyq/k4KxQG6MJMTn3JroZtM2+BUvki6l847xhCdPt1Jrvg8slc0uKI28Cox3XA==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-calculate": "~35.1.37", + "@syncfusion/ej2-charts": "~35.1.37", + "@syncfusion/ej2-dropdowns": "~35.1.37", + "@syncfusion/ej2-grids": "~35.1.37", + "@syncfusion/ej2-interactive-chat": "~35.1.37", + "@syncfusion/ej2-navigations": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-svg-base": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-svg-base/-/ej2-svg-base-35.1.37.tgz", + "integrity": "sha512-jgTjelQSmDHETQfXaecRL92tw/i63ijnACZEwp97gDl+bbY8Nc/PjTvaHNjECjuOL2Nt83q4z77OnGjE2zmNJQ==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-tailwind3-theme": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-tailwind3-theme/-/ej2-tailwind3-theme-35.1.37.tgz", + "integrity": "sha512-1Qujjxkeo4pH58CcBHytkqwTuZZRlFeoEfdzyfkvZGjtcg9dH2sOMYVwz6GVs4dRrtm/KJkqeBXMToCMR6bT2g==", + "license": "SEE LICENSE IN license" + }, + "node_modules/@syncfusion/ej2-vue-base": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-vue-base/-/ej2-vue-base-35.1.37.tgz", + "integrity": "sha512-/S1JqCYTD4VS4vtmDr0HgZCV7IWCTw2O2TdTwRfCMHUbtIZ8QSPg0CRjcPFgH4cXtCgUgGRbMr6sSOButl2Pug==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37" + } + }, + "node_modules/@syncfusion/ej2-vue-spreadsheet": { + "version": "35.1.37", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-vue-spreadsheet/-/ej2-vue-spreadsheet-35.1.37.tgz", + "integrity": "sha512-TZlBx1qAf0t89djagCozYyEVnhq81PeVQtnRgmnCJ7pUo7+OJCMZOXJRilno6SNSK6XkhGm1ryZ0wRL8GTamew==", + "license": "SEE LICENSE IN license", + "dependencies": { + "@syncfusion/ej2-base": "~35.1.37", + "@syncfusion/ej2-spreadsheet": "35.1.37", + "@syncfusion/ej2-vue-base": "~35.1.37" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.19.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.19.0.tgz", + "integrity": "sha512-zY+5tKxXdhGh1PYI0ac+7juvEu4OI6vWtVVoj5i2m42jxAY1U+zHGt6QCyOFwykdP62sM3MJ9stoYYUw5aCWew==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.9.tgz", + "integrity": "sha512-rD/MORlhaZMlXWW0rEn4FB4wMinWC0z/D7Ye160S5+Rs1mC8ZDAdcDp4SjKfUhG5t8q1ktcPVw4xuTkPRlzrSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/language-core": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.28" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz", + "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.43", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.43.tgz", + "integrity": "sha512-zdiLhnbe1QQqgDT8xZMpNmyqZ3qlI+/Q/FHQco57Kwl/b05HhCzN6eVGN9QU9rbga4CrS0H5SYY8VGHZCt/1Hg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@vue/shared": "3.5.43", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.43", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.43.tgz", + "integrity": "sha512-PEZoAk3NQmsn/ejMzSOCyTYqwGqczrWm70PuhBKjjv1+TCoQAaO/zOqNwjV+honlNstT5ILxtc+8r8UUfj+iEQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.43", + "@vue/shared": "3.5.43" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.43", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.43.tgz", + "integrity": "sha512-FCbrG3XNCRl+js3huuKx4IVHBLTvMkJhVepjbxSPu1gn4yWLaYtGNQdjJGZaMytXB6qb76qQDDmDSLy/vkmleQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@vue/compiler-core": "3.5.43", + "@vue/compiler-dom": "3.5.43", + "@vue/compiler-ssr": "3.5.43", + "@vue/shared": "3.5.43", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.28", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.43", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.43.tgz", + "integrity": "sha512-GF62orf7KiJX9RqrHNGrYBudsQGD0OhJ5nDs90O8UiDuS40+YMYomiXu6w6EuvtXuRDc3MSNis3EaaSKAVSWpg==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.43", + "@vue/shared": "3.5.43" + } + }, + "node_modules/@vue/language-core": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.3.11.tgz", + "integrity": "sha512-QJmpliwAVpC/OxubIByPAhNzsQPRc8/gxlN2qnVzVfIMjMDz/9RnXRFoetjz5yEgXVXyp4LqhXq3V53PjmNzFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "@vue/compiler-dom": "^3.5.0", + "@vue/shared": "^3.5.0", + "alien-signals": "^3.2.1", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1", + "picomatch": "^4.0.4" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.43", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.43.tgz", + "integrity": "sha512-G/c9GyOZNI2jVaaS6OX1EF1SSFSv7H0ERqNTl4+DTFMlZmB5eVAB53aLQNam/7NL2NPtaDD7RdVrzf8uJzMuOA==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.43" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.43", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.43.tgz", + "integrity": "sha512-hU6U6VnVhBGQDpvlnnDlIB8ZGJBiOcgk2lh/0InltHiz3D8oSkluvuvY+do1G2H3+udeKFsmaBlgVYP7gXQzEw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.43", + "@vue/shared": "3.5.43" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.43", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.43.tgz", + "integrity": "sha512-Bb2Jc0YjjJdMt1SJmb9b2L/IWd3I8lIT9x9eS/xvvP9CiVgna0ffua74xKRmt4/uSJ+0r4iN8ex1jrqkhQGWQw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.43", + "@vue/runtime-core": "3.5.43", + "@vue/shared": "3.5.43", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.43", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.43.tgz", + "integrity": "sha512-l2Ygjv9NehV94PSBxNWsAHC0j/eIIKbn92mBuWXAPGLnn6HfJ6MH5ubsd+Nk0YoZ5FRuxWI1P2VSoh+dbPQhCQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.43", + "@vue/runtime-dom": "3.5.43", + "@vue/shared": "3.5.43" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.43", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.43.tgz", + "integrity": "sha512-uksS7YGMR5NZyr4JNq0Rp+QyLns0ueaz20KwzIPW9R0LH1Vnt4E+XUM29PNseEbf1www2gOuhuDi5AKOIXag9Q==", + "license": "MIT" + }, + "node_modules/@vue/tsconfig": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.8.1.tgz", + "integrity": "sha512-aK7feIWPXFSUhsCP9PFqPyFOcz4ENkb8hZ2pneL6m2UjCkccvaOhC/5KCKluuBufvp2KzkbdA2W2pk20vLzu3g==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": "5.x", + "vue": "^3.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/alien-signals": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.2.1.tgz", + "integrity": "sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fetch-cookie": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-2.2.0.tgz", + "integrity": "sha512-h9AgfjURuCgA2+2ISl8GbavpUdR+WGAM2McW/ovn4tVccegp8ZqCKWSBR8uRdM8dDNlx5WdKRWxBYUwteLDCNQ==", + "license": "Unlicense", + "dependencies": { + "set-cookie-parser": "^2.4.8", + "tough-cookie": "^4.0.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.19", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", + "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.28", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", + "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.18", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "license": "MIT" + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.63.5.tgz", + "integrity": "sha512-KRWwmNLlPw5M7HcdYfm15oBv9n9LPtjzpzCIxS/phwqvPyxHSoKX6Y2YU3pxSPfy0CLquVgsx/j/hBi6OvH1Nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.63.5", + "@rollup/rollup-android-arm64": "4.63.5", + "@rollup/rollup-darwin-arm64": "4.63.5", + "@rollup/rollup-darwin-x64": "4.63.5", + "@rollup/rollup-freebsd-arm64": "4.63.5", + "@rollup/rollup-freebsd-x64": "4.63.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.63.5", + "@rollup/rollup-linux-arm-musleabihf": "4.63.5", + "@rollup/rollup-linux-arm64-gnu": "4.63.5", + "@rollup/rollup-linux-arm64-musl": "4.63.5", + "@rollup/rollup-linux-loong64-gnu": "4.63.5", + "@rollup/rollup-linux-loong64-musl": "4.63.5", + "@rollup/rollup-linux-ppc64-gnu": "4.63.5", + "@rollup/rollup-linux-ppc64-musl": "4.63.5", + "@rollup/rollup-linux-riscv64-gnu": "4.63.5", + "@rollup/rollup-linux-riscv64-musl": "4.63.5", + "@rollup/rollup-linux-s390x-gnu": "4.63.5", + "@rollup/rollup-linux-x64-gnu": "4.63.5", + "@rollup/rollup-linux-x64-musl": "4.63.5", + "@rollup/rollup-openbsd-x64": "4.63.5", + "@rollup/rollup-openharmony-arm64": "4.63.5", + "@rollup/rollup-win32-arm64-msvc": "4.63.5", + "@rollup/rollup-win32-ia32-msvc": "4.63.5", + "@rollup/rollup-win32-x64-gnu": "4.63.5", + "@rollup/rollup-win32-x64-msvc": "4.63.5", + "fsevents": "~2.3.2" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/vite": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", + "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0 || ^0.28.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vscode-uri": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.2.0.tgz", + "integrity": "sha512-m2gXo3bn0G1kT9InzMf07fTbqMbGtyckj3bH5ktLO+1Ssv+yiATZ4dhwaQv9UZWxJh6E9IFGnQyjgWVDWVBDrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue": { + "version": "3.5.43", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.43.tgz", + "integrity": "sha512-o5qZoksdnjIKvW1srZ3ab7pcDNYAerBjRe54D0LBLfRdCYFrSgBHVXokMas35czQc0//lmx4/tuY4ZNQ+Rf2Ng==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.43", + "@vue/compiler-sfc": "3.5.43", + "@vue/runtime-dom": "3.5.43", + "@vue/server-renderer": "3.5.43", + "@vue/shared": "3.5.43" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-tsc": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.3.11.tgz", + "integrity": "sha512-gOb0B9rtU2+f1dszwPqSH5kAieIF9ReeLhD3kSRNHv5WZZUQz/JdVXW0RTdqhNTMlQkqKzrTTviqKr/4FYZraQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/typescript": "2.4.28", + "@vue/language-core": "3.3.11" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/ws": { + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", + "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/client/vue/package.json b/client/vue/package.json new file mode 100644 index 0000000..282e3ef --- /dev/null +++ b/client/vue/package.json @@ -0,0 +1,27 @@ +{ + "name": "vue-spreadsheet-collaborative-editing", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vue-tsc -b && vite build", + "preview": "vite preview" + }, + "dependencies": { + "@microsoft/signalr": "^9.0.0", + "@syncfusion/ej2-collaborator": "35.1.37", + "@syncfusion/ej2-spreadsheet": "35.1.37", + "@syncfusion/ej2-tailwind3-theme": "35.1.37", + "@syncfusion/ej2-vue-spreadsheet": "35.1.37", + "vue": "^3.5.22" + }, + "devDependencies": { + "@types/node": "^24.7.0", + "@vitejs/plugin-vue": "^6.0.1", + "@vue/tsconfig": "^0.8.1", + "typescript": "~5.9.3", + "vite": "^7.1.9", + "vue-tsc": "^3.1.1" + } +} diff --git a/client/vue/src/App.vue b/client/vue/src/App.vue new file mode 100644 index 0000000..6c04bbf --- /dev/null +++ b/client/vue/src/App.vue @@ -0,0 +1,102 @@ + + + diff --git a/client/vue/src/SpreadsheetEditorAdapter.ts b/client/vue/src/SpreadsheetEditorAdapter.ts new file mode 100644 index 0000000..16b703a --- /dev/null +++ b/client/vue/src/SpreadsheetEditorAdapter.ts @@ -0,0 +1,83 @@ +import type { + ICollaborationActionData, + ICollaborationProvider +} from '@syncfusion/ej2-collaborator'; +import type { Spreadsheet } from '@syncfusion/ej2-spreadsheet'; + +interface ImportFileResponse { + sfdt: string; + version: number; +} + +export class SpreadsheetEditorAdapter implements ICollaborationProvider { + public currentRoomName: string = ''; + + public constructor( + private spreadsheet: Spreadsheet, + private serviceUrl: string, + private currentUser: string + ) { + this.serviceUrl = serviceUrl.endsWith('/') + ? serviceUrl + : serviceUrl + '/'; + } + + public async loadFromServer( + fileName: string, + roomName: string + ): Promise { + const response: Response = await fetch( + this.serviceUrl + 'api/CollaborativeEditing/ImportFile', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ fileName, roomName }) + } + ); + + if (!response.ok) { + throw new Error('Failed to load the workbook.'); + } + + const data: ImportFileResponse = JSON.parse( + await response.text() + ); + + this.currentRoomName = roomName; + this.spreadsheet.collaborativeEditingModule.updateRoomInfo( + roomName, + data.version, + this.serviceUrl + 'api/CollaborativeEditing/' + ); + this.spreadsheet.collaborativeEditingModule.setLocalUser( + this.currentUser + ); + this.spreadsheet.openFromJson({ file: data.sfdt }); + } + + public sendActionToServer(action: unknown): void { + if (!action) { + return; + } + + this.spreadsheet.collaborativeEditingModule.sendActionToServer( + action + ); + } + + public applyRemoteAction( + action: string, + data: ICollaborationActionData + ): void { + if (!data) { + return; + } + + this.spreadsheet.collaborativeEditingModule.applyRemoteAction( + action, + data.payload + ); + } +} diff --git a/client/vue/src/main.ts b/client/vue/src/main.ts new file mode 100644 index 0000000..8dd6bc1 --- /dev/null +++ b/client/vue/src/main.ts @@ -0,0 +1,5 @@ +import { createApp } from 'vue'; +import App from './App.vue'; +import './style.css'; + +createApp(App).mount('#app'); diff --git a/client/vue/src/style.css b/client/vue/src/style.css new file mode 100644 index 0000000..997bf1a --- /dev/null +++ b/client/vue/src/style.css @@ -0,0 +1,8 @@ +@import '@syncfusion/ej2-tailwind3-theme/styles/tailwind3.css'; + +html, +body, +#app { + height: 100%; + margin: 0; +} diff --git a/client/vue/src/vite-env.d.ts b/client/vue/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/client/vue/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/client/vue/tsconfig.app.json b/client/vue/tsconfig.app.json new file mode 100644 index 0000000..7357af2 --- /dev/null +++ b/client/vue/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "strict": true, + "noEmit": true + } +} diff --git a/client/vue/tsconfig.json b/client/vue/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/client/vue/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/client/vue/tsconfig.node.json b/client/vue/tsconfig.node.json new file mode 100644 index 0000000..3950b4b --- /dev/null +++ b/client/vue/tsconfig.node.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "strict": true + }, + "include": ["vite.config.ts"] +} diff --git a/client/vue/vite.config.ts b/client/vue/vite.config.ts new file mode 100644 index 0000000..0a4f24e --- /dev/null +++ b/client/vue/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite'; +import vue from '@vitejs/plugin-vue'; + +export default defineConfig({ + plugins: [vue()] +}); diff --git a/license b/license new file mode 100644 index 0000000..4e57cc0 --- /dev/null +++ b/license @@ -0,0 +1,10 @@ +Essential JS 2 library is available under the Syncfusion Essential Studio program, and can be licensed either under the Syncfusion Community License Program or the Syncfusion commercial license. + +To be qualified for the Syncfusion Community License Program you must have a gross revenue of less than one (1) million U.S. dollars ($1,000,000.00 USD) per year and have less than five (5) developers in your organization, and agree to be bound by Syncfusion’s terms and conditions. + +Customers who do not qualify for the community license can contact sales@syncfusion.com for commercial licensing options. + +Under no circumstances can you use this product without (1) either a Community License or a commercial license and (2) without agreeing and abiding by Syncfusion’s license containing all terms and conditions. + +The Syncfusion license that contains the terms and conditions can be found at +https://www.syncfusion.com/content/downloads/syncfusion_license.pdf \ No newline at end of file diff --git a/server/aspnet-core-redis/Adapters/SpreadsheetCollaborativeAdaptor.cs b/server/aspnet-core-redis/Adapters/SpreadsheetCollaborativeAdaptor.cs new file mode 100644 index 0000000..e69de29 diff --git a/server/aspnet-core-redis/Controllers/CollaborativeEditingController.cs b/server/aspnet-core-redis/Controllers/CollaborativeEditingController.cs new file mode 100644 index 0000000..e69de29 diff --git a/server/aspnet-core-redis/Models/SpreadsheetSelectionInfo.cs b/server/aspnet-core-redis/Models/SpreadsheetSelectionInfo.cs new file mode 100644 index 0000000..e69de29 diff --git a/server/aspnet-core-redis/Program.cs b/server/aspnet-core-redis/Program.cs new file mode 100644 index 0000000..7356400 --- /dev/null +++ b/server/aspnet-core-redis/Program.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.AspNetCore.ResponseCompression; +using Microsoft.AspNetCore.Http.Features; +using Newtonsoft.Json.Serialization; +using Syncfusion.Licensing; +using Microsoft.Extensions.Hosting; +using Syncfusion.Collaboration.Core.Extensions; +using Syncfusion.Collaboration.Core.Interfaces; + +var builder = WebApplication.CreateBuilder(args); + +// Configuration Setup +var env = builder.Environment; +builder.Configuration.SetBasePath(env.ContentRootPath) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) + .AddEnvironmentVariables(); + +// Syncfusion License Registration +string licenseKey = string.Empty; +string licenseFilePath = Path.Combine(Directory.GetCurrentDirectory(), "SyncfusionLicense.txt"); +if (File.Exists(licenseFilePath)) +{ + // Assigning Syncfusion LICENSE_KEY from local file + licenseKey = File.ReadAllText(licenseFilePath).Trim(); +} +if (string.IsNullOrEmpty(licenseKey)) +{ + // Access LICENSE_KEY from environment variables + licenseKey = builder.Configuration["SYNCFUSION_LICENSE_KEY"]; +} + +SyncfusionLicenseProvider.RegisterLicense(licenseKey); + +builder.Services.AddCollaborationServer(options => +{ + options.ConnectionString = builder.Configuration.GetConnectionString("Redis"); + options.ConnectionType = CollaborationConnectionType.SignalR; +}); +builder.Services.AddSingleton(); +builder.Services.AddSignalR(); + +// Configure services +var MyAllowSpecificOrigins = "AllowAllOrigins"; +builder.Services.AddCors(options => +{ + options.AddPolicy(name: MyAllowSpecificOrigins, + builder => { + builder.AllowAnyOrigin() + .AllowAnyMethod() + .AllowAnyHeader(); + }); +}); + +builder.Services.Configure(options => +{ + options.MultipartBodyLengthLimit = int.MaxValue; + options.ValueLengthLimit = int.MaxValue; +}); + +builder.WebHost.ConfigureKestrel(options => +{ + options.Limits.MaxRequestBodySize = int.MaxValue; +}); + +builder.Services.AddMemoryCache(); +builder.Services.AddMvc(endPoint => endPoint.EnableEndpointRouting = false); +builder.Services.AddEndpointsApiExplorer(); + +builder.Services.Configure(options => +{ + options.Level = System.IO.Compression.CompressionLevel.Optimal; +}); +builder.Services.AddResponseCompression(); + +builder.Services.AddControllers().AddNewtonsoftJson(options => +{ + options.SerializerSettings.ContractResolver = new DefaultContractResolver(); +}); + +// Build app +var app = builder.Build(); + +// Middleware +if (!app.Environment.IsDevelopment()) +{ + app.UseExceptionHandler("/Error"); + app.UseHsts(); +} +else +{ + app.UseDeveloperExceptionPage(); +} + +app.UseHttpsRedirection(); +app.UseRouting(); +app.UseCors(MyAllowSpecificOrigins); +app.UseAuthorization(); +app.UseResponseCompression(); +app.MapControllers(); +app.MapCollaborationServer(); +app.Run(); diff --git a/server/aspnet-core-redis/Properties/launchSettings.json b/server/aspnet-core-redis/Properties/launchSettings.json new file mode 100644 index 0000000..bb27f4d --- /dev/null +++ b/server/aspnet-core-redis/Properties/launchSettings.json @@ -0,0 +1,45 @@ +{ + "profiles": { + "EJ2SpreadsheetServer": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "api/test", + "environmentVariables": { + "SYNCFUSION_LICENSE_KEY": "", + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:7002;http://localhost:5209" + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "api/test", + "environmentVariables": { + "SYNCFUSION_LICENSE_KEY": "", + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Container (Dockerfile)": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/api/test", + "environmentVariables": { + "SYNCFUSION_LICENSE_KEY": "", + "ASPNETCORE_URLS": "https://+:443;http://+:80", + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "publishAllPorts": true, + "useSSL": true + } + }, + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:37531", + "sslPort": 44318 + } + } +} \ No newline at end of file diff --git a/server/aspnet-core-redis/SpreadsheetCollaborativeEditing.Server.csproj b/server/aspnet-core-redis/SpreadsheetCollaborativeEditing.Server.csproj new file mode 100644 index 0000000..e69de29 diff --git a/server/aspnet-core-redis/appsettings.Development.json b/server/aspnet-core-redis/appsettings.Development.json new file mode 100644 index 0000000..723c096 --- /dev/null +++ b/server/aspnet-core-redis/appsettings.Development.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/server/aspnet-core-redis/appsettings.json b/server/aspnet-core-redis/appsettings.json new file mode 100644 index 0000000..00d7350 --- /dev/null +++ b/server/aspnet-core-redis/appsettings.json @@ -0,0 +1,19 @@ +{ + "SYNCFUSION_LICENSE_KEY": "", + "ConnectionStrings": { + "Redis": "redis-276188.redis.cache.windows.net:6380,password=pRIeJHlNcxzuD1Yz1ClZ00Ol3X4H2YdkmAzCaBuDaQY=,ssl=True,abortConnect=False" + }, + "Logging": { + "IncludeScopes": false, + "Debug": { + "LogLevel": { + "Default": "Warning" + } + }, + "Console": { + "LogLevel": { + "Default": "Warning" + } + } + } +} diff --git a/server/aspnet-core-redis/wwwroot/Files/Sample.xlsx b/server/aspnet-core-redis/wwwroot/Files/Sample.xlsx new file mode 100644 index 0000000..a4b2c7c Binary files /dev/null and b/server/aspnet-core-redis/wwwroot/Files/Sample.xlsx differ