diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..54e4783 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.json] +indent_size = 2 + +[*.{yml,yaml}] +indent_size = 2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..663e695 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +* text=auto eol=lf + +# Keep Windows shell scripts with CRLF for compatibility. +*.bat text eol=crlf +*.cmd text eol=crlf +*.ps1 text eol=crlf diff --git a/.github/workflows/ghp.yml b/.github/workflows/ghp.yml new file mode 100644 index 0000000..3aa4930 --- /dev/null +++ b/.github/workflows/ghp.yml @@ -0,0 +1,86 @@ +name: GitHub Pages +on: + push: + branches: [ "outlook" ] + workflow_dispatch: + inputs: + VITE_IO_BRIDGE_URL: + description: 'Optional bridge URL override for this run (e.g. https://bridge.example.com)' + required: false + type: string + +#concurrency: +# group: pages +# cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + + permissions: + contents: read + id-token: write + + steps: + - name: Checkout bridge-examples + uses: actions/checkout@v6 + with: + path: bridge-examples + - name: Checkout connect-js + uses: actions/checkout@v6 + with: + repository: InteropIO/connect-js + ref: feature/upgrade-gateway + token: '${{ secrets.PAT }}' + path: connect-js + + - name: Use Node 20 for connect-js build + uses: actions/setup-node@v6 + with: + node-version: 20 + cache: npm + cache-dependency-path: connect-js/package-lock.json + + - name: Build connect-js + working-directory: connect-js/ + env: + LICENSE_KEY: ${{ secrets.IO_CB_LICENSE_KEY }} + run: | + npm ci + npm run build + + - name: Use project Node version for office build + uses: actions/setup-node@v6 + with: + node-version-file: bridge-examples/.node-version + cache: npm + cache-dependency-path: bridge-examples/office/package-lock.json + - name: Install dependencies + working-directory: bridge-examples/office + run: npm ci + - name: Build + working-directory: bridge-examples/office + run: npm run build + env: + VITE_IO_BRIDGE_URL: ${{ github.event.inputs.VITE_IO_BRIDGE_URL || vars.VITE_IO_BRIDGE_URL }} + VITE_AUTH0_DOMAIN: ${{ secrets.AUTH0_DOMAIN }} + VITE_AUTH0_CLIENT_ID: ${{ secrets.AUTH0_CLIENT_ID }} + VITE_AUTH0_AUDIENCE: ${{ secrets.AUTH0_AUDIENCE }} + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v4 + with: + path: bridge-examples/office/dist + + deploy: + needs: build + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..490bca4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +.env +.secrets/ diff --git a/.node-version b/.node-version new file mode 100644 index 0000000..d845d9d --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +24.14.0 diff --git a/README.md b/README.md deleted file mode 100644 index 8fc2084..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# bridge-examples -io.Bridge Examples diff --git a/office/.env.example b/office/.env.example new file mode 100644 index 0000000..d99a162 --- /dev/null +++ b/office/.env.example @@ -0,0 +1,135 @@ +## This is an example .env file for io.Bridge +## Copy this file as .env and fill in the required values + +############################################################################### +## License key for io.Bridge ## +############################################################################### + +## License key for io.Bridge (Required). Specify it as a string. +IO_BRIDGE_LICENSE_KEY= +## Alternatively, you can specify the path to a file containing the license key. +#IO_BRIDGE_LICENSE_KEY_FILE=./.secrets/io-bridge-license.key + +############################################################################### +## Server ## +############################################################################### + +## The PORT for io.Bridge server to bind on (Optional, default is 8084) +#IO_BRIDGE_SERVER_PORT=8385 + +## The host for io.Bridge server to bind on (Optional, default is '0.0.0.0' i.e. any local IP) +#IO_BRIDGE_SERVER_HOST=127.0.0.1 + +## The path to file where the resolved io.Bridge server is bound (Optional) +#IO_BRIDGE_PRINT_PORT=./io-bridge-address.json + +############################################################################### +## Auth ## +############################################################################### + +## Authentication type. For example 'none', 'basic' or 'oauth2' +#IO_BRIDGE_SERVER_AUTH_TYPE=oauth2 + +## Basic Authentication Realm +IO_BRIDGE_SERVER_AUTH_BASIC_REALM=interop.io + +## +#IO_BRIDGE_SERVER_AUTH_OAUTH2_JWT_ISSUERURI= + +## +IO_BRIDGE_SERVER_AUTH_OAUTH2_JWT_AUDIENCE= +## Same as the one above, but exposed to the client +VITE_AUTH0_AUDIENCE= + +## Client ID for Auth0 SPA application +#VITE_AUTH0_CLIENT_ID= + +## Domain for Auth0 tenant +#VITE_AUTH0_DOMAIN= + +## +#VITE_AUTH0_SCOPES=openid email + +############################################################################### +## Mesh ## +############################################################################### + +## The ping interval for mesh (Optional, default is 30s) +#IO_BRIDGE_MESH_PING_INTERVAL=30s + +############################################################################### +## Gateway ## +############################################################################### + +## If you want to embed gateway (Optional, default is false) +#IO_BRIDGE_GATEWAY_ENABLED=true + +############################################################################### +## CORS ## +############################################################################### + +## Allow origins for CORS (Optional, default is *) +## The special value * allows all origins. +## You can also specify multiple origins separated by commas. +## You can use regular expressions to match origins, for example: +## - http:\/\/localhost(:d+)? matches http://localhost, http://localhost:8080, etc. +## - file:\/\/.* matches any file URL +## - null is a way to support specific 'null' origin set by the client, for example when using about:blank in a browser +#IO_BRIDGE_SERVER_CORS_ALLOW_ORIGIN=/http:\/\/localhost(:d+)?/,/file:\/\/.*/,null + +## Allow methods for CORS (Optional, default is GET,HEAD). The special value * allows all methods. +#IO_BRIDGE_SERVER_CORS_ALLOW_METHODS=GET,POST,DELETE + +## Which headers a pre-flight request can list as allowed for use during an actual request. (Optional, default is *) +#IO_BRIDGE_SERVER_CORS_ALLOW_HEADERS=* + +## Which headers that an actual response might have and can be exposed to the clients (Optional) +#IO_BRIDGE_SERVER_CORS_EXPOSE_HEADERS=X-Authorization + +## How long (in seconds) response from a pre-flight request can be cached by clients (Optional, default is 3600 i.e. 1 hour) +#IO_BRIDGE_SERVER_CORS_MAX_AGE=3600 + +## If you want to allow credentials in CORS (Optional, default is false), cannot be true if allow origins is set to * +## Setting this to true will impact how allow origins, methods and headers are processed +#IO_BRIDGE_SERVER_CORS_ALLOW_CREDENTIALS=true + +## If you want to allow private network access (PNA) in CORS (Optional, default is false), cannot be true if allow origins is set to * +#IO_BRIDGE_SERVER_CORS_ALLOW_PRIVATE_NETWORK=true + +## If you want to completely disable CORS handling (Optional, default is false) +#IO_BRIDGE_SERVER_CORS_DISABLED=true + +############################################################################### +## Logging +############################################################################### + +## This is the logging layout to use. The default is 'ecs' which is the Elastic Common Schema. +## Other options are 'logstash' +LOGGING_LAYOUT=ecs + +## The logging level to use. The default is 'info'. +## Supported levels are: trace, debug, info, warn, error and off +#LOGGING_LEVEL=debug + +#LOGGING_LEVEL_GATEWAY_BRIDGE=debug +#LOGGING_LEVEL_GATEWAY_SERVER=info +#LOGGING_LEVEL_GATEWAY_SERVER_HTTP=debug + +LOGGING_LEVEL_GATEWAY=info + +############################################################################### +## Web App Configuration (Vite) +## Variables prefixed with VITE_ are exposed to the browser (required by Vite) +############################################################################### + +## License key for io.Connect Browser Platform (Required for web app) +## Note: This is a DIFFERENT license than IO_BRIDGE_LICENSE_KEY above. +## - IO_BRIDGE_LICENSE_KEY is for the io.Bridge server (Node.js) +## - VITE_IO_CB_LICENSE_KEY is for the browser platform (client-side) +VITE_IO_CB_LICENSE_KEY= + +## io.Bridge URL for browser platform connection (Optional, default is https://localhost:8084) +#VITE_IO_BRIDGE_URL=https://localhost:8084 +VITE_AUTH0_DOMAIN= +VITE_AUTH0_CLIENT_ID= +VITE_AUTH0_AUDIENCE= diff --git a/office/.gitignore b/office/.gitignore new file mode 100644 index 0000000..353b3fa --- /dev/null +++ b/office/.gitignore @@ -0,0 +1,3 @@ +dist/ +node_modules/ +public/static/modals/ diff --git a/office/auth0/app.ts b/office/auth0/app.ts new file mode 100644 index 0000000..e5afb24 --- /dev/null +++ b/office/auth0/app.ts @@ -0,0 +1,123 @@ +import type { ServerConfigurer } from '@interopio/gateway-server/web/server'; +import type { Logger } from '@interopio/gateway/logging/api'; +import { randomUUID } from 'node:crypto'; +import { readFileSync } from 'node:fs'; +import { resolve } from 'node:path'; + +export type AuthInfo = { + user: string + username?: string, + token?: string | null + headers?: Record +} + +const successPage = readFileSync(resolve(import.meta.dirname, './success.html')).toString(); + +// --------------------------------------------------------------------------- +// Auth0 integration — Implicit Flow with response_mode=form_post +// +// GET /login/auth0 → redirects to Auth0 Universal Login +// POST /api/webhooks/auth0/callback → Auth0 POSTs tokens back here +// --------------------------------------------------------------------------- +export const app = async ( + config: { + logger: Logger, + issuerUrl: string, + clientId: string, + scopes?: string, + audience?: string, + authInfoResolver: (data: AuthInfo) => void, + }, + { + handle + }: ServerConfigurer +) => { + const { logger, issuerUrl, clientId } = config; + const scopes = config.scopes ?? 'openid email'; + const loginCallbackPath = '/login/oauth2/code/auth0'; + const loginUrlPath = '/login/auth0'; + + logger.info(`auth0 login endpoint registered on [${loginUrlPath}]`); + logger.info(`auth0 callback endpoint registered on [${loginCallbackPath}]`); + + handle( + // --------------------------------------------------------------- + // GET /login/auth0 — redirect to Auth0 Universal Login + // --------------------------------------------------------------- + { + request: { method: 'GET', path: loginUrlPath }, + options: { authorize: { access: 'permitted' } }, + handler: async ({ request, response }) => { + + const nonce = randomUUID(); + const state = randomUUID(); + const redirectUri = `${request.protocol}://${request.host}${loginCallbackPath}`; + logger.info('initiating Auth0 implicit login flow', { redirectUri }); + + const authorizeUrl = `${issuerUrl}/authorize?` + new URLSearchParams({ + response_type: 'id_token token', + response_mode: 'form_post', + client_id: clientId, + redirect_uri: redirectUri, + scope: scopes, + state, + nonce, + audience: config.audience ?? `io.bridge`, + + }).toString(); + + logger.info(`redirecting to Auth0: ${authorizeUrl}`); + response.setRawStatusCode(302); + response.headers.set('Location', authorizeUrl); + await response.end(); + } + }, + // --------------------------------------------------------------- + // POST /login/oauth2/code/auth0 — Auth0 posts tokens here + // --------------------------------------------------------------- + { + request: { method: 'POST', path: loginCallbackPath }, + options: { authorize: { access: 'permitted' } }, + handler: async ({ request, response }) => { + const formData = await request.formData(); + + const error = formData.get('error'); + const errorDescription = formData.get('error_description'); + + if (error) { + logger.warn(`auth0 error: ${error} — ${errorDescription}`); + response.setRawStatusCode(400); + await response.body(new TextEncoder().encode( + `Auth0 login failed: ${error} — ${errorDescription ?? 'unknown error'}` + )); + await response.end(); + return; + } + + const idToken = formData.get('id_token'); + let user = 'dev-user'; + let username; + if (idToken) { + const payload = JSON.parse(Buffer.from(idToken.split('.')[1], 'base64').toString()); + user = payload.email; + username = payload.name; + } + username ??= user; + + // set authInfo with the received tokens and user + config.authInfoResolver({ + token: formData.get('access_token'), + user, + username + }); + + response.setRawStatusCode(200); + response.headers.set('Content-Type', 'text/html'); + + + await response.body(new TextEncoder().encode(successPage.replace('${username}', `${username} (${user})`))); + await response.end(); + } + } + ); +} diff --git a/office/auth0/readme.md b/office/auth0/readme.md new file mode 100644 index 0000000..e69de29 diff --git a/office/auth0/success.html b/office/auth0/success.html new file mode 100644 index 0000000..a3e5514 --- /dev/null +++ b/office/auth0/success.html @@ -0,0 +1,60 @@ + + + + + + Login Successful + + + + +
+
+

Login Successful

+

Welcome, ${username}!

+

This window will close in 5 seconds…

+
+ + + + diff --git a/office/gateway-server.config.ts b/office/gateway-server.config.ts new file mode 100644 index 0000000..4beba5c --- /dev/null +++ b/office/gateway-server.config.ts @@ -0,0 +1,155 @@ +import { defineConfig } from "@interopio/gateway-server/config"; + +import { tmpdir } from "node:os"; +import opener from "opener"; + +import * as IOGatewayLogging from "@interopio/gateway/logging/core"; +import type { ServerConfigurer } from "@interopio/gateway-server/web/server"; + +import type { AuthInfo } from "./auth0/app.ts"; +import { app } from "./auth0/app.ts"; + +process.loadEnvFile(); +const BRIDGE_URL = process.env["VITE_IO_BRIDGE_URL"] ?? "https://gw-bridge-examples.interop.io"; + +let authInfoResolver: (data: AuthInfo) => void; +const authInfoPromise: Promise = new Promise((resolve) => { + authInfoResolver = resolve; +}); + + +const host = "127.0.0.1"; // accessible only locally for security reasons +const port = 8385; // same port as io.Connect Desktop's default gateway port +const IO_CD_ENV = "DEMO"; +const IO_CD_REGION = "INTEROP.IO"; + +// +// import { createServer } from "node:net"; +// const server = createServer((client) => { +// let info = JSON.stringify({endpoint: `ws://${host}:${port}/`, pid: process.pid}); +// console.log(`sending info... ${info}`); +// client.write(info, "utf8"); +// client.end(); +// client.destroy(); +// }); +// server.listen((() => { +// if (process.platform === 'win32') { +// return `\\\\.\\pipe\\glue42-${IO_CD_ENV}-${IO_CD_REGION}-${process.env.USERNAME}`; +// } else { +// return `${tmpdir()}/glue42-${IO_CD_ENV}-${IO_CD_REGION}-${process.env.USER}.sock`; +// } +// })()); + +function requireNonEmptyEnvVariable(envVarName: string): string { + const value = process.env[envVarName]; + if (!value) { + throw new Error(`Environment variable ${envVarName} is required but not set.`); + } + return value; +} + +export default defineConfig({ + host, + port, + cors: false, + auth: { + type: "none" + }, + + gateway: { + authentication: { + basic: { + usernameResolver: async(_login) => { + const { user } = await authInfoPromise; + return user; + } + } + }, + contexts: { + visibility: [ + { context: /___channel___.+/, restrictions: 'cluster' }, + { context: /T42\..*/, restrictions: 'local' }, + { context: /___workspace___.+/, restrictions: 'local' }, + { context: /___window-hibernation___.+/, restrictions: 'local' }, + { context: /___instance___.+/, restrictions: 'local' }, + { context: /___window___.+/, restrictions: 'local' }, + { restrictions: 'cluster' } + ], + }, + + methods: { + visibility: [ + { identity: { application: "Outlook" }, restrictions: "cluster" }, + { identity: { application: "IOXLAddin" }, restrictions: "cluster" }, + { method: /T42\..*/, restrictions: 'local' }, + { + restrictions: "local" + } + ] + }, + peers: { + visibility: [ + { domain: "context", restrictions: "cluster" }, + { domain: "interop", restrictions: "cluster" }, + { domain: "bus", restrictions: "local" } + ] + }, + mesh: { + enabled: true, + + auth: { + // auth0 config and data + }, + cluster: { + endpoint: BRIDGE_URL, + opts: { + getHeaders: async () => { + const headers: Record = {}; + const auth0FlowData = await authInfoPromise; + if (auth0FlowData.token) { + headers["Authorization"] = `Bearer ${auth0FlowData.token}`; + } + return headers; + }, + }, + }, + + }, + + }, + + management: { + server: { + path: (() => { + if (process.platform === 'win32') { + return `\\\\.\\pipe\\gateway-server-${IO_CD_ENV}-${IO_CD_REGION}-${process.env.USERNAME}`; + } else { + return `${tmpdir()}/gateway-server-${IO_CD_ENV}-${IO_CD_REGION}-${process.env.USER}.sock`; + } + })() + }, + commands: { + shutdown: { + enabled: true, + } + } + }, + + app: async (configurer: ServerConfigurer) => { + + await app( + { + logger: IOGatewayLogging.getLogger('gateway.bridge.auth0'), + authInfoResolver: authInfoResolver, + issuerUrl: requireNonEmptyEnvVariable('IO_BRIDGE_SERVER_AUTH_OAUTH2_JWT_ISSUERURI'), + clientId: requireNonEmptyEnvVariable('VITE_AUTH0_CLIENT_ID'), + audience: requireNonEmptyEnvVariable('IO_BRIDGE_SERVER_AUTH_OAUTH2_JWT_AUDIENCE'), + scopes: process.env.VITE_AUTH0_SCOPES ?? 'openid email', + }, + configurer + ); + + } +}); + +opener(`http://localhost:${port}/login/auth0`); diff --git a/office/package-lock.json b/office/package-lock.json new file mode 100644 index 0000000..d693991 --- /dev/null +++ b/office/package-lock.json @@ -0,0 +1,3204 @@ +{ + "name": "@interopio/bridge-example-office", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@interopio/bridge-example-office", + "license": "MIT", + "dependencies": { + "@auth0/auth0-react": "^2.0.2", + "@interopio/browser": "file:../../connect-js/packages/browser", + "@interopio/browser-platform": "file:../../connect-js/packages/browser-platform", + "@interopio/core": "file:../../connect-js/packages/core", + "@interopio/home-ui-react": "^4.2.8-next.0", + "@interopio/modals-ui": "^4.2.8-next.0", + "@interopio/search-api": "file:../../connect-js/packages/search-api", + "@interopio/workspaces-ui-react": "^4.2.8-next.0", + "react": "^19.2.4", + "react-dom": "^19.2.4" + }, + "devDependencies": { + "@interopio/bridge": "^1.1.2", + "@interopio/desktop": "^6.16.3", + "@interopio/gateway": "^0.25.1", + "@interopio/gateway-server": "^0.24.0", + "@types/node": "^24.12.0", + "@types/opener": "^1.4.3", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "concurrently": "^9.2.1", + "opener": "^1.5.2", + "rimraf": "^6.1.3", + "typescript": "^5.9.3", + "vite": "^8.0.1" + }, + "engines": { + "node": ">=24.0.0" + } + }, + "../../connect-js/packages/browser": { + "name": "@interopio/browser", + "version": "4.2.5", + "license": "MIT", + "dependencies": { + "@interopio/core": "^6.9.0", + "@interopio/desktop": "^6.14.0", + "@interopio/modals-api": "^4.2.8-next.0", + "@interopio/search-api": "^3.2.2", + "@interopio/workspaces-api": "^4.2.8-next.0", + "callback-registry": "^2.7.2" + }, + "devDependencies": { + "@interopio/utils": "^2.2.0" + }, + "peerDependencies": { + "@interopio/insights-base": "0.0.*", + "@interopio/insights-instrumentations-web": "0.0.*", + "@interopio/insights-logs": "0.0.*", + "@interopio/insights-metrics": "0.0.*", + "@interopio/insights-traces": "0.0.*" + }, + "peerDependenciesMeta": { + "@interopio/insights-base": { + "optional": true + }, + "@interopio/insights-instrumentations-web": { + "optional": true + }, + "@interopio/insights-logs": { + "optional": true + }, + "@interopio/insights-metrics": { + "optional": true + }, + "@interopio/insights-traces": { + "optional": true + } + } + }, + "../../connect-js/packages/browser-platform": { + "name": "@interopio/browser-platform", + "version": "4.2.5", + "license": "Commercial", + "dependencies": { + "@interopio/browser": "^4.2.5", + "@interopio/core": "^6.9.0", + "@interopio/desktop": "^6.14.0" + }, + "devDependencies": { + "@interopio/search-api": "^3.2.2", + "@interopio/utils": "^2.2.0" + } + }, + "../../connect-js/packages/core": { + "name": "@interopio/core", + "version": "6.9.0", + "license": "MIT", + "dependencies": { + "@interopio/otel": "0.0.*", + "callback-registry": "^2.7.2", + "ws": "^8.18.0" + }, + "peerDependencies": { + "@interopio/insights-base": "0.0.*", + "@interopio/insights-instrumentations-web": "0.0.*", + "@interopio/insights-logs": "0.0.*", + "@interopio/insights-metrics": "0.0.*", + "@interopio/insights-traces": "0.0.*" + }, + "peerDependenciesMeta": { + "@interopio/insights-base": { + "optional": true + }, + "@interopio/insights-instrumentations-web": { + "optional": true + }, + "@interopio/insights-logs": { + "optional": true + }, + "@interopio/insights-metrics": { + "optional": true + }, + "@interopio/insights-traces": { + "optional": true + } + } + }, + "../../connect-js/packages/search-api": { + "name": "@interopio/search-api", + "version": "3.2.2", + "license": "MIT", + "dependencies": { + "@interopio/core": "^6.9.0" + } + }, + "node_modules/@accessible/use-id": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@accessible/use-id/-/use-id-1.1.2.tgz", + "integrity": "sha512-0JcdE3a9WuR0hf8EfvoDDcKROOYEklSh9HN8nEQuAuyRQ7FrVYKDOz966nUiknzT4wy7MD4IkbdhkC4LqLhwHA==", + "license": "MIT", + "dependencies": { + "@react-hook/passive-layout-effect": "^1.2.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/@auth0/auth0-auth-js": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@auth0/auth0-auth-js/-/auth0-auth-js-1.5.0.tgz", + "integrity": "sha512-shahG7sRw6VxduRvnNcmbgL8V42z+kNR9LDih9ofY4eM8ygt07RUh58x7S1M80ENx9wcMqYUsJWMaVudgQHyjQ==", + "license": "MIT", + "dependencies": { + "jose": "^6.0.8", + "openid-client": "^6.8.0" + } + }, + "node_modules/@auth0/auth0-react": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/@auth0/auth0-react/-/auth0-react-2.15.1.tgz", + "integrity": "sha512-zcBh8xWO1cgUeN19tQueZHVzq7/O+yWc6MhKdQvoU0ima0wagl9SeyVmahg8aiBQqRcqT6C+y2+IOcnPGnI2Vw==", + "license": "MIT", + "dependencies": { + "@auth0/auth0-spa-js": "^2.17.1" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17 || ^18 || ~19.0.1 || ~19.1.2 || ^19.2.1", + "react-dom": "^16.11.0 || ^17 || ^18 || ~19.0.1 || ~19.1.2 || ^19.2.1" + } + }, + "node_modules/@auth0/auth0-spa-js": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/@auth0/auth0-spa-js/-/auth0-spa-js-2.18.0.tgz", + "integrity": "sha512-2oKnn6cD4zQUWDfZ4bWWmLxEbOnxjMYakMFOJCJ5Z5OobVeOBtUTVkYKB8LaDksQrK3F41IRzcP97ffsqEUYEA==", + "license": "MIT", + "dependencies": { + "@auth0/auth0-auth-js": "1.5.0", + "browser-tabs-lock": "1.3.0", + "dpop": "2.1.1", + "es-cookie": "1.3.2" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz", + "integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", + "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", + "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache/node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emotion/memoize": "0.7.4" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "license": "MIT", + "optional": true + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/serialize/node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.26.28", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.28.tgz", + "integrity": "sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.8", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.6" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "license": "MIT" + }, + "node_modules/@interopio/bridge": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@interopio/bridge/-/bridge-1.1.2.tgz", + "integrity": "sha512-w+w6aQW8s5vmNcv8e3PbhCLqu/kFFt9MT3tn3sQTuSkCyqB8bCrDNS6tNQ/EG8B4haoXGqr0+W2ZzZfISYOe3A==", + "dev": true, + "license": "see license in license.md", + "dependencies": { + "@interopio/gateway-server": "^0.24.0", + "hrw-hash": "^2.0.3", + "jsrsasign": "^11.1.1", + "nanoid": "^5.1.7" + }, + "bin": { + "io-bridge": "bin/bridge.js" + }, + "engines": { + "node": "^20.18.0 || ^22.2.0 || >=24" + } + }, + "node_modules/@interopio/browser": { + "resolved": "../../connect-js/packages/browser", + "link": true + }, + "node_modules/@interopio/browser-platform": { + "resolved": "../../connect-js/packages/browser-platform", + "link": true + }, + "node_modules/@interopio/components-react": { + "version": "4.2.8-next.0", + "resolved": "https://registry.npmjs.org/@interopio/components-react/-/components-react-4.2.8-next.0.tgz", + "integrity": "sha512-J4wVUbheTRveVFKfX+IRlyiVs3FxP8wnZHUQEGuj6W5GeFmMNovjazoqosNXdbjUi2ckMBKZ8vj3PW3dUnHDrw==", + "license": "MIT", + "dependencies": { + "@accessible/use-id": "^1.1.2", + "@floating-ui/react": "^0.26.24", + "callback-registry": "^2.7.2", + "classnames": "^2.3.2", + "date-fns": "^4.1.0", + "decoder-validate": "^0.0.2", + "framer-motion": "^6.5.1", + "react-select": "^5.8.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@interopio/desktop": "^6.16.3", + "@interopio/react-hooks": "^4.2.8-next.0", + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@interopio/react-hooks": { + "optional": true + } + } + }, + "node_modules/@interopio/core": { + "resolved": "../../connect-js/packages/core", + "link": true + }, + "node_modules/@interopio/desktop": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@interopio/desktop/-/desktop-6.18.0.tgz", + "integrity": "sha512-YqRHRiCymbY2fOCT2HHJnLY4780JSRI1fUtaWEoIa5Z3djZk/3xRgVxIjOVw9Y/TAFGCwyIeW142a7HYnSGD5Q==", + "license": "MIT", + "dependencies": { + "@interopio/core": "^6.8.1", + "@interopio/schemas": "^10.1.0", + "@interopio/utils": "^1.4.2", + "@interopio/workspaces-api": "^4.2.3", + "callback-registry": "^2.7.1" + } + }, + "node_modules/@interopio/desktop/node_modules/@interopio/workspaces-api": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@interopio/workspaces-api/-/workspaces-api-4.2.4.tgz", + "integrity": "sha512-v/KKkud+ip/FNBtecxFpzhHaoUUv3pAvH7Dk5q2s8Duxq8Wd6thzQjMbX7a6w+PKY3Vnmijx7jWrnhu6GLyuaA==", + "license": "MIT" + }, + "node_modules/@interopio/gateway": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@interopio/gateway/-/gateway-0.25.1.tgz", + "integrity": "sha512-dol92KBZsVVb/xzab48UFbeKhEfcCcP+prFg8p3L0LtLuPzzDUMuzB9cykJLbd3DYnPX0fml5XcQraH50qbSIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "antlr4": "4.13.2", + "immer": "^11.1.4", + "jsrsasign": "^11.1.1", + "serialize-error": "^13.0.1", + "type-fest": "^5.4.4" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "transit-js": "^0.8.874" + } + }, + "node_modules/@interopio/gateway-server": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@interopio/gateway-server/-/gateway-server-0.24.0.tgz", + "integrity": "sha512-ZjKL4ZTzsqYfsOODoe54KlGBRmYabnCP2gAXFU7rvgTuhYFrmMnvY5kSwbsYq1seXWGG94oZa74KXEB5Zm08zw==", + "dev": true, + "license": "see license in license.md", + "dependencies": { + "@interopio/gateway": "^0.25.1", + "http-cookie-agent": "^7.0.3", + "tough-cookie": "^6.0.1", + "ws": "^8.19.0" + }, + "bin": { + "gateway-server": "bin/gateway-server.cjs" + }, + "engines": { + "node": ">=20.18 || >=22.12 || >=24" + }, + "peerDependencies": { + "undici": "^7.24.4" + }, + "peerDependenciesMeta": { + "undici": { + "optional": true + } + } + }, + "node_modules/@interopio/home-ui-react": { + "version": "4.2.8-next.0", + "resolved": "https://registry.npmjs.org/@interopio/home-ui-react/-/home-ui-react-4.2.8-next.0.tgz", + "integrity": "sha512-Z0bq6VoT1xPliseq1EO66hzGuQYfzvOabI6cw/UMjMijEKXMbUcMX141OrXTOOHyXBYvkVl6g3Ns2sSuG2Pk6w==", + "license": "MIT", + "dependencies": { + "@interopio/components-react": "^4.2.8-next.0", + "decoder-validate": "^0.0.2", + "ua-parser-js": "^1.0.35" + }, + "peerDependencies": { + "@auth0/auth0-react": "^2.0.1", + "@interopio/browser": ">=3.0.0", + "@interopio/browser-platform": ">=3.0.0", + "@interopio/react-hooks": ">=4.2.8-next.0", + "@interopio/search-api": ">=3.0.0", + "@interopio/workspaces-api": ">=4.2.8-next.0", + "@interopio/workspaces-ui-react": ">=4.2.8-next.0", + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@interopio/browser": { + "optional": true + }, + "@interopio/browser-platform": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@interopio/modals-api": { + "version": "4.2.8-next.0", + "resolved": "https://registry.npmjs.org/@interopio/modals-api/-/modals-api-4.2.8-next.0.tgz", + "integrity": "sha512-wB5vIeQDgEjZ+VXM3XLFHLW+EAeNPjAA6EZvWUkSm37n50iNQrDInqAq33pN/fqcNOSdFCVNbujR4/MRdcLP3A==", + "license": "MIT" + }, + "node_modules/@interopio/modals-ui": { + "version": "4.2.8-next.0", + "resolved": "https://registry.npmjs.org/@interopio/modals-ui/-/modals-ui-4.2.8-next.0.tgz", + "integrity": "sha512-w3OksIw8PqlB3b2kyfF7q0ZZ92moz8/jgF26YP7MEeKHeCaenjTL67hA7XSf0RutTlTsD+JIzOwyuXQemv9+6w==", + "dependencies": { + "@interopio/components-react": "^4.2.8-next.0", + "@interopio/modals-api": "^4.2.8-next.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@interopio/react-hooks": { + "version": "4.2.8-next.0", + "resolved": "https://registry.npmjs.org/@interopio/react-hooks/-/react-hooks-4.2.8-next.0.tgz", + "integrity": "sha512-4Mzv2xwzCVEvW4e9uM/JSQ0X4e2WKqUYaZ0a4OdNF4B3ZQpN1n6xhbSxmLfFeBBwa1YMW3tblZTjo73gIDS0Rg==", + "license": "MIT", + "peer": true, + "dependencies": { + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "@interopio/browser": ">=3.0.0", + "@interopio/browser-platform": ">=3.0.0", + "@interopio/desktop": ">=5.0.0", + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@interopio/browser": { + "optional": true + }, + "@interopio/browser-platform": { + "optional": true + }, + "@interopio/desktop": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@interopio/schemas": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@interopio/schemas/-/schemas-10.1.0.tgz", + "integrity": "sha512-8uDEoOAZenTr4a3O8vLq6JyS/LutkT/gh9EjuOrS9fOmHEUfJaS2u+qPo5em9/8MtjKgblZEJStSsW1gr34CtQ==", + "license": "ISC", + "dependencies": { + "ajv": "^6.12.6", + "ajv-keywords": "^3.4.1" + }, + "peerDependencies": { + "log4js": "^6.4.2" + }, + "peerDependenciesMeta": { + "log4js": { + "optional": true + } + } + }, + "node_modules/@interopio/search-api": { + "resolved": "../../connect-js/packages/search-api", + "link": true + }, + "node_modules/@interopio/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@interopio/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-14Bb2WI9Cwf9zjhTurP4qP9AVY4cxR1AOrwrOtHrTGAeeHp88mALFWfMEv1QnRhlQ06To2vQcRgebNrPlHDZ8Q==", + "license": "ISC", + "dependencies": { + "decoder-validate": "^0.0.2" + } + }, + "node_modules/@interopio/workspaces-api": { + "version": "4.2.8-next.0", + "resolved": "https://registry.npmjs.org/@interopio/workspaces-api/-/workspaces-api-4.2.8-next.0.tgz", + "integrity": "sha512-wTYhZmKm3G6X0iF7gd8iWwNbF53WIvIWNo6fuw+umWQh5Q9ULI0YREMVbGP8L00vi8364gb7E0otwqXv2Nu0/Q==", + "license": "MIT", + "peer": true + }, + "node_modules/@interopio/workspaces-ui-react": { + "version": "4.2.8-next.0", + "resolved": "https://registry.npmjs.org/@interopio/workspaces-ui-react/-/workspaces-ui-react-4.2.8-next.0.tgz", + "integrity": "sha512-7pLGs7p1/XiKToj1N9CZ25o98cglYmA+TcBbIIxWZlW8YEu0Ph++xEbINs7/akUqlfvhxYmt4rPaQzaiSLRofg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@interopio/react-hooks": ">=4.2.8-next.0", + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@interopio/react-hooks": { + "optional": true + }, + "react": { + "autoinstall": false + }, + "react-dom": { + "autoinstall": false + } + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@motionone/animation": { + "version": "10.18.0", + "resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.18.0.tgz", + "integrity": "sha512-9z2p5GFGCm0gBsZbi8rVMOAJCtw1WqBTIPw3ozk06gDvZInBPIsQcHgYogEJ4yuHJ+akuW8g1SEIOpTOvYs8hw==", + "license": "MIT", + "dependencies": { + "@motionone/easing": "^10.18.0", + "@motionone/types": "^10.17.1", + "@motionone/utils": "^10.18.0", + "tslib": "^2.3.1" + } + }, + "node_modules/@motionone/dom": { + "version": "10.12.0", + "resolved": "https://registry.npmjs.org/@motionone/dom/-/dom-10.12.0.tgz", + "integrity": "sha512-UdPTtLMAktHiqV0atOczNYyDd/d8Cf5fFsd1tua03PqTwwCe/6lwhLSQ8a7TbnQ5SN0gm44N1slBfj+ORIhrqw==", + "license": "MIT", + "dependencies": { + "@motionone/animation": "^10.12.0", + "@motionone/generators": "^10.12.0", + "@motionone/types": "^10.12.0", + "@motionone/utils": "^10.12.0", + "hey-listen": "^1.0.8", + "tslib": "^2.3.1" + } + }, + "node_modules/@motionone/easing": { + "version": "10.18.0", + "resolved": "https://registry.npmjs.org/@motionone/easing/-/easing-10.18.0.tgz", + "integrity": "sha512-VcjByo7XpdLS4o9T8t99JtgxkdMcNWD3yHU/n6CLEz3bkmKDRZyYQ/wmSf6daum8ZXqfUAgFeCZSpJZIMxaCzg==", + "license": "MIT", + "dependencies": { + "@motionone/utils": "^10.18.0", + "tslib": "^2.3.1" + } + }, + "node_modules/@motionone/generators": { + "version": "10.18.0", + "resolved": "https://registry.npmjs.org/@motionone/generators/-/generators-10.18.0.tgz", + "integrity": "sha512-+qfkC2DtkDj4tHPu+AFKVfR/C30O1vYdvsGYaR13W/1cczPrrcjdvYCj0VLFuRMN+lP1xvpNZHCRNM4fBzn1jg==", + "license": "MIT", + "dependencies": { + "@motionone/types": "^10.17.1", + "@motionone/utils": "^10.18.0", + "tslib": "^2.3.1" + } + }, + "node_modules/@motionone/types": { + "version": "10.17.1", + "resolved": "https://registry.npmjs.org/@motionone/types/-/types-10.17.1.tgz", + "integrity": "sha512-KaC4kgiODDz8hswCrS0btrVrzyU2CSQKO7Ps90ibBVSQmjkrt2teqta6/sOG59v7+dPnKMAg13jyqtMKV2yJ7A==", + "license": "MIT" + }, + "node_modules/@motionone/utils": { + "version": "10.18.0", + "resolved": "https://registry.npmjs.org/@motionone/utils/-/utils-10.18.0.tgz", + "integrity": "sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw==", + "license": "MIT", + "dependencies": { + "@motionone/types": "^10.17.1", + "hey-listen": "^1.0.8", + "tslib": "^2.3.1" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", + "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.122.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.122.0.tgz", + "integrity": "sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@react-hook/passive-layout-effect": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@react-hook/passive-layout-effect/-/passive-layout-effect-1.2.1.tgz", + "integrity": "sha512-IwEphTD75liO8g+6taS+4oqz+nnroocNfWVHWz7j+N+ZO2vYrc6PV1q7GQhuahL0IOR7JccFTsFKQ/mb6iZWAg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.11.tgz", + "integrity": "sha512-SJ+/g+xNnOh6NqYxD0V3uVN4W3VfnrGsC9/hoglicgTNfABFG9JjISvkkU0dNY84MNHLWyOgxP9v9Y9pX4S7+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.11.tgz", + "integrity": "sha512-7WQgR8SfOPwmDZGFkThUvsmd/nwAWv91oCO4I5LS7RKrssPZmOt7jONN0cW17ydGC1n/+puol1IpoieKqQidmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.11.tgz", + "integrity": "sha512-39Ks6UvIHq4rEogIfQBoBRusj0Q0nPVWIvqmwBLaT6aqQGIakHdESBVOPRRLacy4WwUPIx4ZKzfZ9PMW+IeyUQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.11.tgz", + "integrity": "sha512-jfsm0ZHfhiqrvWjJAmzsqiIFPz5e7mAoCOPBNTcNgkiid/LaFKiq92+0ojH+nmJmKYkre4t71BWXUZDNp7vsag==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.11.tgz", + "integrity": "sha512-zjQaUtSyq1nVe3nxmlSCuR96T1LPlpvmJ0SZy0WJFEsV4kFbXcq2u68L4E6O0XeFj4aex9bEauqjW8UQBeAvfQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.11.tgz", + "integrity": "sha512-WMW1yE6IOnehTcFE9eipFkm3XN63zypWlrJQ2iF7NrQ9b2LDRjumFoOGJE8RJJTJCTBAdmLMnJ8uVitACUUo1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.11.tgz", + "integrity": "sha512-jfndI9tsfm4APzjNt6QdBkYwre5lRPUgHeDHoI7ydKUuJvz3lZeCfMsI56BZj+7BYqiKsJm7cfd/6KYV7ubrBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.11.tgz", + "integrity": "sha512-ZlFgw46NOAGMgcdvdYwAGu2Q+SLFA9LzbJLW+iyMOJyhj5wk6P3KEE9Gct4xWwSzFoPI7JCdYmYMzVtlgQ+zfw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.11.tgz", + "integrity": "sha512-hIOYmuT6ofM4K04XAZd3OzMySEO4K0/nc9+jmNcxNAxRi6c5UWpqfw3KMFV4MVFWL+jQsSh+bGw2VqmaPMTLyw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.11.tgz", + "integrity": "sha512-qXBQQO9OvkjjQPLdUVr7Nr2t3QTZI7s4KZtfw7HzBgjbmAPSFwSv4rmET9lLSgq3rH/ndA3ngv3Qb8l2njoPNA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.11.tgz", + "integrity": "sha512-/tpFfoSTzUkH9LPY+cYbqZBDyyX62w5fICq9qzsHLL8uTI6BHip3Q9Uzft0wylk/i8OOwKik8OxW+QAhDmzwmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.11.tgz", + "integrity": "sha512-mcp3Rio2w72IvdZG0oQ4bM2c2oumtwHfUfKncUM6zGgz0KgPz4YmDPQfnXEiY5t3+KD/i8HG2rOB/LxdmieK2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.11.tgz", + "integrity": "sha512-LXk5Hii1Ph9asuGRjBuz8TUxdc1lWzB7nyfdoRgI0WGPZKmCxvlKk8KfYysqtr4MfGElu/f/pEQRh8fcEgkrWw==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.11.tgz", + "integrity": "sha512-dDwf5otnx0XgRY1yqxOC4ITizcdzS/8cQ3goOWv3jFAo4F+xQYni+hnMuO6+LssHHdJW7+OCVL3CoU4ycnh35Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.11.tgz", + "integrity": "sha512-LN4/skhSggybX71ews7dAj6r2geaMJfm3kMbK2KhFMg9B10AZXnKoLCVVgzhMHL0S+aKtr4p8QbAW8k+w95bAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.7", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", + "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/node": { + "version": "24.12.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.0.tgz", + "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/opener": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@types/opener/-/opener-1.4.3.tgz", + "integrity": "sha512-g7TYSmy2RKZkU3QT/9pMISrhVmQtMNaYq6Aojn3Y6pht29Nu9VuijJCYIjofRj7ZaFtKdxh1I8xf3vdW4l86fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", + "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-rc.7" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/antlr4": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.2.tgz", + "integrity": "sha512-QiVbZhyy4xAZ17UPEuG3YTOt8ZaoeOR1CvEAqrEsDBsOqINslaB147i9xqljZqoyf5S+EUlGStaj+t22LT9MOg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=16" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/browser-tabs-lock": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-tabs-lock/-/browser-tabs-lock-1.3.0.tgz", + "integrity": "sha512-g6nHaobTiT0eMZ7jh16YpD2kcjAp+PInbiVq3M1x6KKaEIVhT4v9oURNIpZLOZ3LQbQ3XYfNhMAb/9hzNLIWrw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "lodash": ">=4.17.21" + } + }, + "node_modules/callback-registry": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/callback-registry/-/callback-registry-2.7.2.tgz", + "integrity": "sha512-VVrtF21DaH0VHeNMkLDd4VGuxsYM3V3l3lwYneKVMU/6X3TRtcQszUwlAcqj2HrLcbP1NyS12LsanUwCykaz/Q==", + "license": "ISC" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concurrently": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", + "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "4.1.2", + "rxjs": "7.8.2", + "shell-quote": "1.8.3", + "supports-color": "8.1.1", + "tree-kill": "1.2.2", + "yargs": "17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "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/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decoder-validate": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/decoder-validate/-/decoder-validate-0.0.2.tgz", + "integrity": "sha512-9BsqAH9Zq6CvlxKHkSrZrH2iYlhuhHcrh6uTnDvcsa9P5YEweEzt1ci+X/9STgSCE7b9BA7/QIiwhfUDDWmjxw==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dpop": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/dpop/-/dpop-2.1.1.tgz", + "integrity": "sha512-J0Of2JTiM4h5si0tlbPQ/lkqfZ5wAEVkKYBhkwyyANnPJfWH4VsR5uIkZ+T+OSPIwDYUg1fbd5Mmodd25HjY1w==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-cookie": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/es-cookie/-/es-cookie-1.3.2.tgz", + "integrity": "sha512-UTlYYhXGLOy05P/vKVT2Ui7WtC7NiRzGtJyAKKn32g5Gvcjn7KAClLPWlipCtxIus934dFg9o9jXiBL0nP+t9Q==", + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "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/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, + "node_modules/framer-motion": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-6.5.1.tgz", + "integrity": "sha512-o1BGqqposwi7cgDrtg0dNONhkmPsUFDaLcKXigzuTFC5x58mE8iyTazxSudFzmT6MEyJKfjjU8ItoMe3W+3fiw==", + "license": "MIT", + "dependencies": { + "@motionone/dom": "10.12.0", + "framesync": "6.0.1", + "hey-listen": "^1.0.8", + "popmotion": "11.0.3", + "style-value-types": "5.0.0", + "tslib": "^2.1.0" + }, + "optionalDependencies": { + "@emotion/is-prop-valid": "^0.8.2" + }, + "peerDependencies": { + "react": ">=16.8 || ^17.0.0 || ^18.0.0", + "react-dom": ">=16.8 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/framesync": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.0.1.tgz", + "integrity": "sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.1.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/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hey-listen": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz", + "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==", + "license": "MIT" + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hrw-hash": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hrw-hash/-/hrw-hash-2.0.3.tgz", + "integrity": "sha512-Xkygc2lmTZyxWycx6fFkxDtfJMnauYFugwkWNnWFo0QbTexWtY6iVSm9n5nALrp3oGvoskwfXxD/YIMQDpsfOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.5.0" + } + }, + "node_modules/http-cookie-agent": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/http-cookie-agent/-/http-cookie-agent-7.0.3.tgz", + "integrity": "sha512-EeZo7CGhfqPW6R006rJa4QtZZUpBygDa2HZH3DJqsTzTjyRE6foDBVQIv/pjVsxHC8z2GIdbB1Hvn9SRorP3WQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.4" + }, + "engines": { + "node": ">=20.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/3846masa" + }, + "peerDependencies": { + "tough-cookie": "^4.0.0 || ^5.0.0 || ^6.0.0", + "undici": "^7.0.0" + }, + "peerDependenciesMeta": { + "undici": { + "optional": true + } + } + }, + "node_modules/immer": { + "version": "11.1.4", + "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.4.tgz", + "integrity": "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jose": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.2.tgz", + "integrity": "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/jsrsasign": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-11.1.1.tgz", + "integrity": "sha512-6w95OOXH8DNeGxakqLndBEqqwQ6A70zGaky1oxfg8WVLWOnghTfJsc5Tknx+Z88MHSb1bGLcqQHImOF8Lk22XA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/kjur/jsrsasign#donations" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "11.2.7", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", + "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.7.tgz", + "integrity": "sha512-ua3NDgISf6jdwezAheMOk4mbE1LXjm1DfMUDMuJf4AqxLFK3ccGpgWizwa5YV7Yz9EpXwEaWoRXSb/BnV0t5dQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/non-error": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/non-error/-/non-error-0.1.0.tgz", + "integrity": "sha512-TMB1uHiGsHRGv1uYclfhivcnf0/PdFp2pNqRxXjncaAsjYMoisaQJI+SSZCqRq+VliwRTC8tsMQfmrWjDMhkPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/oauth4webapi": { + "version": "3.8.5", + "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.8.5.tgz", + "integrity": "sha512-A8jmyUckVhRJj5lspguklcl90Ydqk61H3dcU0oLhH3Yv13KpAliKTt5hknpGGPZSSfOwGyraNEFmofDYH+1kSg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "license": "(WTFPL OR MIT)", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/openid-client": { + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-6.8.2.tgz", + "integrity": "sha512-uOvTCndr4udZsKihJ68H9bUICrriHdUVJ6Az+4Ns6cW55rwM5h0bjVIzDz2SxgOI84LKjFyjOFvERLzdTUROGA==", + "license": "MIT", + "dependencies": { + "jose": "^6.1.3", + "oauth4webapi": "^3.8.4" + }, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/popmotion": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.3.tgz", + "integrity": "sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA==", + "license": "MIT", + "dependencies": { + "framesync": "6.0.1", + "hey-listen": "^1.0.8", + "style-value-types": "5.0.0", + "tslib": "^2.1.0" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "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.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "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/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "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/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-select": { + "version": "5.10.2", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.10.2.tgz", + "integrity": "sha512-Z33nHdEFWq9tfnfVXaiM12rbJmk+QjFEztWLtmXqQhz6Al4UZZ9xc0wiatmGtUOCCnHN0WizL3tCMYRENX4rVQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.2.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/rimraf": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", + "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "glob": "^13.0.3", + "package-json-from-dist": "^1.0.1" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.11.tgz", + "integrity": "sha512-NRjoKMusSjfRbSYiH3VSumlkgFe7kYAa3pzVOsVYVFY3zb5d7nS+a3KGQ7hJKXuYWbzJKPVQ9Wxq2UvyK+ENpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.122.0", + "@rolldown/pluginutils": "1.0.0-rc.11" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.11", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.11", + "@rolldown/binding-darwin-x64": "1.0.0-rc.11", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.11", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.11", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.11", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.11", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.11", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.11", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.11", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.11", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.11", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.11", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.11", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.11" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.11.tgz", + "integrity": "sha512-xQO9vbwBecJRv9EUcQ/y0dzSTJgA7Q6UVN7xp6B81+tBGSLVAK03yJ9NkJaUA7JFD91kbjxRSC/mDnmvXzbHoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/serialize-error": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-13.0.1.tgz", + "integrity": "sha512-bBZaRwLH9PN5HbLCjPId4dP5bNGEtumcErgOX952IsvOhVPrm3/AeK1y0UHA/QaPG701eg0yEnOKsCOC6X/kaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "non-error": "^0.1.0", + "type-fest": "^5.4.1" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/style-value-types": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-5.0.0.tgz", + "integrity": "sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA==", + "license": "MIT", + "dependencies": { + "hey-listen": "^1.0.8", + "tslib": "^2.1.0" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tabbable": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz", + "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==", + "license": "MIT" + }, + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tldts": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.27.tgz", + "integrity": "sha512-I4FZcVFcqCRuT0ph6dCDpPuO4Xgzvh+spkcTr1gK7peIvxWauoloVO0vuy1FQnijT63ss6AsHB6+OIM4aXHbPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.0.27" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.27.tgz", + "integrity": "sha512-YQ7uPjgWUibIK6DW5lrKujGwUKhLevU4hcGbP5O6TcIUb+oTjJYJVWPS4nZsIHrEEEG6myk/oqAJUEQmpZrHsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", + "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/transit-js": { + "version": "0.8.874", + "resolved": "https://registry.npmjs.org/transit-js/-/transit-js-0.8.874.tgz", + "integrity": "sha512-IDJJGKRzUbJHmN0P15HBBa05nbKor3r2MmG6aSt0UxXIlJZZKcddTk67/U7WyAeW9Hv/VYI02IqLzolsC4sbPA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-fest": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.5.0.tgz", + "integrity": "sha512-PlBfpQwiUvGViBNX84Yxwjsdhd1TUlXr6zjX7eoirtCPIr08NAmxwa+fcYBTeRQxHo9YC9wwF3m9i700sHma8g==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/ua-parser-js": { + "version": "1.0.41", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.41.tgz", + "integrity": "sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", + "bin": { + "ua-parser-js": "script/cli.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz", + "integrity": "sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/vite": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.2.tgz", + "integrity": "sha512-1gFhNi+bHhRE/qKZOJXACm6tX4bA3Isy9KuKF15AgSRuRazNBOJfdDemPBU16/mpMxApDPrWvZ08DcLPEoRnuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.8", + "rolldown": "1.0.0-rc.11", + "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", + "@vitejs/devtools": "^0.1.0", + "esbuild": "^0.27.0", + "jiti": ">=1.21.0", + "less": "^4.0.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 + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "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/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/ws": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/office/package.json b/office/package.json new file mode 100644 index 0000000..faf1e9b --- /dev/null +++ b/office/package.json @@ -0,0 +1,58 @@ +{ + "name": "@interopio/bridge-example-office", + "private": true, + "description": "io.Bridge example demonstrating Outlook integration from a web app", + "type": "module", + "scripts": { + "build": "tsc && vite build", + "clean": "rimraf dist", + "start:bridge": "npx @interopio/bridge --server-port 8084", + "start:gateway": "npx @interopio/gateway-server run --debug", + "start:web": "vite --host", + "start": "concurrently \"npm:start:bridge\" \"npm:start:gateway\" \"npm:start:web\"", + "start:no-gateway": "concurrently \"npm:start:bridge\" \"npm:start:web\"", + "start:no-bridge": "concurrently \"npm:start:gateway\" \"npm:start:web\"", + "dev": "npm run start:web", + "preview": "vite preview" + }, + "keywords": [ + "io.bridge", + "outlook", + "gateway", + "interop", + "example" + ], + "author": "InteropIO", + "license": "MIT", + "dependencies": { + "@auth0/auth0-react": "^2.0.2", + "@interopio/browser": "file:../../connect-js/packages/browser", + "@interopio/browser-platform": "file:../../connect-js/packages/browser-platform", + "@interopio/core": "file:../../connect-js/packages/core", + "@interopio/home-ui-react": "^4.2.8-next.0", + "@interopio/modals-ui": "^4.2.8-next.0", + "@interopio/search-api": "file:../../connect-js/packages/search-api", + "@interopio/workspaces-ui-react": "^4.2.8-next.0", + "react": "^19.2.4", + "react-dom": "^19.2.4" + }, + "devDependencies": { + "@interopio/bridge": "^1.1.2", + "@interopio/desktop": "^6.16.3", + "@interopio/gateway": "^0.25.1", + "@interopio/gateway-server": "^0.24.0", + "@types/node": "^24.12.0", + "@types/opener": "^1.4.3", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "concurrently": "^9.2.1", + "opener": "^1.5.2", + "rimraf": "^6.1.3", + "typescript": "^5.9.3", + "vite": "^8.0.1" + }, + "engines": { + "node": ">=24.0.0" + } +} diff --git a/office/readme.md b/office/readme.md new file mode 100644 index 0000000..9c7df53 --- /dev/null +++ b/office/readme.md @@ -0,0 +1,668 @@ +# io.Bridge Outlook Integration Example + +This example demonstrates how to use io.Bridge to send emails via Outlook from a web app hosted in io.Connect Browser. + +## Overview + +The example consists of: +- **Local io.Bridge** (`@interopio/bridge`): Local bridge instance running on 127.0.0.1 +- **Desktop Gateway Server** (`@interopio/gateway-server`): Hosts a desktop gateway that connects to the local bridge and interfaces with Outlook +- **Browser Platform** (Web App): React-based UI using `@interopio/home-ui-react` that bootstraps `@interopio/browser-platform` +- **Outlook Add-in**: Downloaded from [InteropIO Outlook Add-in v1.318.0.0](https://github.com/InteropIO/iocd-components/releases/download/outlook-v1.318.0.0-win32/outlook-v1.318.0.0-win32.zip) +- **Excel Add-in**: Downloaded from [InteropIO Excel Add-in v1.318.0.0](https://github.com/InteropIO/iocd-components/releases/download/excel-v1.26.0320.1751-win32/excel-v1.26.0320.1751-win32.zip) +- **SSO Provider** (Optional): Third-party authentication (Auth0 or custom OAuth2/OIDC) for production-realistic demo + +## Architecture + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Browser (HTTPS - GitHub Pages or localhost) │ +│ ┌──────────────────────────────────────────────────────────┐ │ +│ │ Web App (@interopio/home-ui-react) │ │ +│ │ ├─ In-Browser Gateway ──────────────────┐ │ │ +│ │ └─ Email Compose UI │ │ │ +│ └──────────────────────────────────────────┼───────────────┘ │ +└─────────────────────────────────────────────┼──────────────────┘ + │ + ▼ + ┌──────────────────────────────────────────┐ + │ Local io.Bridge (@interopio/bridge) │ + │ Running on 127.0.0.1:8080 │ + │ (Optional SSO Protection) │ + └──────────────────────────────────────────┘ + ▲ + │ +┌─────────────────────────────────────────────┼──────────────────┐ +│ Desktop (Windows - localhost) │ │ +│ ┌──────────────────────────────────────────┼───────────────┐ │ +│ │ Gateway Server (@interopio/gateway-server) │ │ +│ │ ├─ Desktop Gateway (connects to bridge) ┘ │ │ +│ │ ├─ Named Pipe Discovery Service │ │ +│ │ └─ OAuth2/OIDC Authentication (optional) │ │ +│ └──────────────────────────────────────────┬───────────────┘ │ +│ │ │ +│ ┌──────────────────────────────────────────▼───────────────┐ │ +│ │ Outlook Component (v1.318.0.0) │ │ +│ │ ├─ GlueInstaller.cmd │ │ +│ │ └─ Connects via Named Pipe Discovery │ │ +│ └──────────────────────────────────────────┬───────────────┘ │ +│ │ │ +│ ┌──────────────────────────────────────────▼───────────────┐ │ +│ │ Microsoft Outlook (COM/REST API) │ │ +│ └──────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +**Note:** This example focuses on the integration concepts and runs everything locally. For production cluster deployment of io.Bridge, refer to the [Docker](../docker/readme.md) and [Kubernetes](../kubernetes/readme.md) examples. + +## Tasks Breakdown + +### Phase 1: Infrastructure Setup + +#### Task 1.1: Local io.Bridge Setup +**Status:** ⏳ Not Started + +**Description:** Set up local io.Bridge instance using `@interopio/bridge` package. + +**Subtasks:** +- [ ] Create `bridge-local` package +- [ ] Install `@interopio/bridge` dependency +- [ ] Create bridge initialization script +- [ ] Configure to run on 127.0.0.1:8080 +- [ ] Add license key configuration +- [ ] (Optional) Add JWT validation middleware for SSO demo +- [ ] Test bridge starts and accepts connections + +**Configuration Example:** +```typescript +// bridge-local/src/index.ts +import { Bridge } from '@interopio/bridge'; + +const bridge = new Bridge({ + port: 8080, + host: '127.0.0.1', + licenseKey: process.env.IO_BRIDGE_LICENSE_KEY +}); + +await bridge.start(); +console.log('io.Bridge running on 127.0.0.1:8080'); +``` + +**Acceptance Criteria:** +- Bridge starts successfully on localhost +- Bridge accepts gateway connections +- License validation works +- Can be started/stopped easily for development + +#### Task 1.2: Gateway Discovery via Named Pipe +**Status:** 🔄 In Progress (Implementation underway) + +**Description:** Implement named pipe discovery service in the gateway-server package to allow the Outlook component to discover the desktop gateway. + +**Subtasks:** +- [ ] Create named pipe server using `@interopio/gateway-server` +- [ ] Implement discovery protocol (gateway announces itself via named pipe) +- [ ] Configure named pipe name/location (e.g., `\\.\pipe\io-gateway-discovery`) +- [ ] Handle multiple gateway instances (if needed) +- [ ] Add error handling and reconnection logic + +**Acceptance Criteria:** +- Outlook component can discover gateway via named pipe +- Gateway announces itself with connection details +- Connection persists across gateway restarts + +#### Task 1.3: Desktop Gateway Server Configuration +**Status:** ⏳ Not Started + +**Description:** Configure gateway-server using `@interopio/gateway-server` to connect to local bridge. + +**Subtasks:** +- [ ] Create gateway-server package configuration +- [ ] Initialize gateway using `@interopio/gateway-server` +- [ ] Configure connection to local bridge (127.0.0.1:8080) +- [ ] Configure named pipe discovery service +- [ ] (Optional) Add OAuth2/OIDC authentication support +- [ ] Implement startup sequence: bridge connection → named pipe announcement + +**Configuration Example:** +```typescript +// gateway-server/src/index.ts +import { GatewayServer } from '@interopio/gateway-server'; + +const gateway = new GatewayServer({ + bridge: { + host: '127.0.0.1', + port: 8080 + }, + discovery: { + type: 'named-pipe', + name: '\\\\.\\pipe\\io-gateway-discovery' + }, + auth: { + enabled: false // or configure OAuth2 for demo + } +}); + +await gateway.start(); +``` + +**Acceptance Criteria:** +- Gateway connects to local bridge +- Named pipe discovery service is active +- Outlook component can discover and connect +- All components run on localhost + +#### Task 1.4: SSO Configuration (Optional for Production Demo) +**Status:** ⏳ Not Started + +**Description:** Add optional SSO authentication to demonstrate production-ready setup. + +**Subtasks:** +- [ ] Choose SSO provider (Auth0 recommended) +- [ ] Add JWT validation to bridge +- [ ] Configure OAuth2 flow in gateway-server +- [ ] Configure OAuth2 flow in browser app +- [ ] Test authentication flow +- [ ] Document SSO setup steps + +**Decision Points:** +- **Auth0 vs Custom:** Auth0 for simplicity, custom for flexibility +- **Demo Mode:** Allow running without SSO for simpler demo +- **Token Management:** Implement refresh token handling + +**Acceptance Criteria:** +- Can run example with or without SSO +- SSO flow works when enabled +- Documentation covers both modes + +### Phase 2: Desktop Gateway Authentication + +#### Task 2.1: OAuth2/OIDC Flow in Gateway Server +**Status:** ⏳ Not Started + +**Description:** Implement OAuth2/OIDC authentication flow in the gateway-server to handle SSO authentication. + +**Subtasks:** +- [ ] Detect 401 response when connecting to io.Bridge +- [ ] Implement OAuth2 authorization code flow with PKCE +- [ ] Launch system browser for user authentication +- [ ] Create local HTTP server to receive callback (e.g., http://localhost:8080/callback) +- [ ] Exchange authorization code for access token +- [ ] Store and refresh access tokens securely +- [ ] Attach access token to bridge connection + +**Authentication Flow:** +``` +1. Gateway starts → Attempts to connect to io.Bridge +2. Receives 401 Unauthorized +3. Generates PKCE challenge +4. Opens browser: https://sso.example.com/authorize?client_id=...&redirect_uri=http://localhost:8080/callback +5. User authenticates in browser +6. Browser redirects to http://localhost:8080/callback?code=... +7. Gateway exchanges code for access token +8. Gateway connects to io.Bridge with token +9. Connection established +``` + +**Subtasks Detail:** +- [ ] Implement PKCE (Proof Key for Code Exchange) for security +- [ ] Handle browser launch cross-platform (Windows primarily) +- [ ] Implement callback server (temporary HTTP server) +- [ ] Store tokens securely (OS keychain/credential manager) +- [ ] Implement token refresh logic +- [ ] Handle authentication errors and retry logic + +**Acceptance Criteria:** +- Gateway prompts for authentication on first run +- Browser opens automatically for user login +- Gateway receives and stores access token +- Gateway successfully connects to io.Bridge with valid token +- Token refresh works automatically + +#### Task 2.2: Token Management and Persistence +**Status:** ⏳ Not Started + +**Description:** Implement secure token storage and automatic refresh. + +**Subtasks:** +- [ ] Use Windows Credential Manager for token storage +- [ ] Implement token expiration detection +- [ ] Implement automatic token refresh before expiration +- [ ] Handle refresh token expiration (re-authenticate) +- [ ] Add logout/revoke functionality + +**Acceptance Criteria:** +- Tokens persist across gateway restarts +- Gateway doesn't prompt for auth if valid token exists +- Automatic refresh works transparently + +### Phase 3: Browser Application + +#### Task 3.1: Web App Scaffolding +**Status:** ⏳ Not Started + +**Description:** Create React-based web application using `@interopio/home-ui-react`. + +**Subtasks:** +- [ ] Initialize React project (Vite or Create React App) +- [ ] Install `@interopio/home-ui-react` +- [ ] Install `@interopio/browser-platform` +- [ ] Create basic project structure +- [ ] Configure build for production deployment + +**Commands:** +```bash +npm create vite@latest outlook-bridge-app -- --template react-ts +cd outlook-bridge-app +npm install @interopio/home-ui-react @interopio/browser-platform +``` + +**Acceptance Criteria:** +- Project builds successfully +- Basic React app runs locally +- Dependencies installed correctly + +#### Task 3.2: Browser Platform Initialization +**Status:** ⏳ Not Started + +**Description:** Bootstrap `@interopio/browser-platform` within the web app. + +**Subtasks:** +- [ ] Configure browser platform with io.Bridge cluster connection +- [ ] Configure authentication (Auth0 or custom OAuth2) +- [ ] Initialize in-browser gateway +- [ ] Configure gateway to connect to io.Bridge cluster +- [ ] Test connection and authentication flow + +**Configuration Example:** +```typescript +import { IOConnectBrowserPlatform } from '@interopio/browser-platform'; + +const config = { + gateway: { + location: 'http://localhost:8080' // Local bridge instance + }, + auth: { + // Optional: Enable for SSO demo + enabled: false + // provider: 'auth0', + // config: { + // domain: 'your-tenant.auth0.com', + // clientId: 'your-client-id', + // redirectUri: window.location.origin + // } + } +}; + +await IOConnectBrowserPlatform(config); +``` + +**Acceptance Criteria:** +- Browser platform initializes successfully +- In-browser gateway connects to io.Bridge +- Authentication flow works in browser +- User can log in and access gateway + +#### Task 3.3: Email Composition UI +**Status:** ⏳ Not Started + +**Description:** Create UI components for composing and sending emails via Outlook. + +**Subtasks:** +- [ ] Create email form component (To, Subject, Body) +- [ ] Add validation for email fields +- [ ] Add "Send Email" button +- [ ] Implement io.Connect method invocation to desktop gateway +- [ ] Add success/error notifications +- [ ] Add optional features (CC, BCC, Attachments) + +**UI Components:** +- Email recipient field (with validation) +- Subject line input +- Rich text or plain text body editor +- Send button with loading state +- Status/error display + +**Acceptance Criteria:** +- Form validates input properly +- Send button invokes interop method +- User receives feedback (success/error) +- UI is responsive and accessible + +#### Task 3.4: Hosting Configuration +**Status:** ⏳ Not Started + +**Description:** Configure hosting for the web application with HTTPS. + +**Options:** +1. **GitHub Pages** (Static Hosting) + - [ ] Configure GitHub Pages in repository settings + - [ ] Set up custom domain (optional) + - [ ] Configure HTTPS (automatic with GitHub Pages) + - [ ] Add deployment workflow (GitHub Actions) + +2. **Local Development with HTTPS** + - [ ] Generate self-signed SSL certificates via gateway-server + - [ ] Configure dev server to use HTTPS + - [ ] Import certificates into browser trust store + - [ ] Document certificate installation process + +**Decision:** GitHub Pages is preferred for production-like demo, local HTTPS for development. + +**GitHub Pages Setup:** +```yaml +# .github/workflows/deploy.yml +name: Deploy to GitHub Pages +on: + push: + branches: [main] +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + - run: npm install + - run: npm run build + - uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./dist +``` + +**Acceptance Criteria:** +- App is accessible via HTTPS +- GitHub Pages deployment works automatically +- Or local HTTPS setup is documented and working + +### Phase 4: Outlook Integration + +#### Task 4.1: Outlook Component Installation +**Status:** ⏳ Not Started + +**Description:** Download, install, and configure the Outlook component. + +**Subtasks:** +- [ ] Download outlook-v1.318.0.0-win32.zip +- [ ] Extract and document contents +- [ ] Run GlueInstaller.cmd with appropriate parameters +- [ ] Configure component to use named pipe discovery +- [ ] Verify component can discover gateway +- [ ] Test basic connectivity + +**Installation Steps:** +```powershell +# Download +Invoke-WebRequest -Uri "https://github.com/InteropIO/iocd-components/releases/download/outlook-v1.318.0.0-win32/outlook-v1.318.0.0-win32.zip" -OutFile outlook.zip + +# Extract +Expand-Archive -Path outlook.zip -DestinationPath .\outlook-component + +# Install (modify GlueInstaller.cmd if needed to use named pipe discovery) +cd outlook-component +.\GlueInstaller.cmd +``` + +**Acceptance Criteria:** +- Component installed successfully +- Component discovers gateway via named pipe +- Component appears in Outlook + +#### Task 4.2: Interop Method Implementation (Desktop) +**Status:** ⏳ Not Started + +**Description:** Implement the interop method in the Outlook component to send emails. + +**Subtasks:** +- [ ] Define interop method schema: `T42.Outlook.SendEmail` +- [ ] Implement method handler in Outlook component +- [ ] Use Outlook COM API or REST API to create email +- [ ] Handle parameters: to, subject, body, cc, bcc, attachments +- [ ] Return success/error status +- [ ] Add logging and error handling + +**Method Schema:** +```typescript +interface SendEmailArgs { + to: string | string[]; + subject: string; + body: string; + cc?: string | string[]; + bcc?: string | string[]; + attachments?: string[]; // File paths + sendImmediately?: boolean; // true = send, false = show draft +} + +interface SendEmailResult { + success: boolean; + messageId?: string; + error?: string; +} +``` + +**Acceptance Criteria:** +- Method registered and discoverable +- Can create draft email in Outlook +- Can send email immediately (if specified) +- Proper error handling for invalid emails + +#### Task 4.3: Interop Method Invocation (Browser) +**Status:** ⏳ Not Started + +**Description:** Implement method invocation from browser app to Outlook component. + +**Subtasks:** +- [ ] Get io.Connect API reference in React app +- [ ] Implement `io.interop.invoke()` call +- [ ] Pass email parameters from form to method +- [ ] Handle async responses +- [ ] Display success/error messages to user +- [ ] Add loading/pending states + +**Implementation Example:** +```typescript +const sendEmail = async (emailData: SendEmailArgs) => { + try { + const result = await io.interop.invoke('T42.Outlook.SendEmail', emailData); + if (result.returned.success) { + showSuccess('Email sent successfully!'); + } else { + showError(result.returned.error || 'Failed to send email'); + } + } catch (error) { + showError('Failed to invoke Outlook: ' + error.message); + } +}; +``` + +**Acceptance Criteria:** +- Browser app can invoke desktop method +- Parameters passed correctly +- Success/error states handled properly +- User experience is smooth + +### Phase 5: Testing & Documentation + +#### Task 5.1: End-to-End Testing +**Status:** ⏳ Not Started + +**Description:** Test the complete flow from browser to Outlook. + +**Test Scenarios:** +- [ ] User authentication (browser and desktop) +- [ ] Gateway discovery via named pipe +- [ ] Browser platform connects to io.Bridge +- [ ] Desktop gateway connects to io.Bridge +- [ ] Method registration and discovery +- [ ] Email sending (draft mode) +- [ ] Email sending (immediate send) +- [ ] Error scenarios (invalid email, Outlook not running, etc.) +- [ ] Reconnection after network interruption +- [ ] Token refresh and re-authentication + +**Acceptance Criteria:** +- All test scenarios pass +- Error handling works as expected +- System recovers from failures gracefully + +#### Task 5.2: Documentation +**Status:** ⏳ Not Started + +**Description:** Create comprehensive documentation for the example. + +**Subtasks:** +- [ ] Update this README with setup instructions +- [ ] Document prerequisites (Outlook version, Windows version, etc.) +- [ ] Document SSO provider setup +- [ ] Document gateway-server configuration +- [ ] Document web app configuration and deployment +- [ ] Create troubleshooting guide +- [ ] Add architecture diagrams +- [ ] Add code comments and JSDoc + +**Documentation Sections:** +- Prerequisites +- Installation & Setup + - SSO Provider Configuration + - io.Bridge Cluster Setup + - Gateway Server Installation + - Outlook Component Installation + - Web App Deployment +- Configuration Reference +- Usage Guide +- Troubleshooting +- API Reference +- Architecture & Design Decisions + +**Acceptance Criteria:** +- Documentation is complete and accurate +- New users can follow instructions successfully +- Common issues are documented + +#### Task 5.3: Security Review +**Status:** ⏳ Not Started + +**Description:** Review security aspects of the implementation. + +**Review Areas:** +- [ ] Token storage security (Windows Credential Manager) +- [ ] Named pipe security (permissions, authentication) +- [ ] Gateway binding (localhost only, no external access) +- [ ] SSL/TLS configuration +- [ ] OAuth2 PKCE implementation +- [ ] Input validation (email parameters) +- [ ] CORS configuration +- [ ] Secrets management (client secrets, license keys) + +**Acceptance Criteria:** +- No sensitive data in code or logs +- Proper authentication and authorization +- Network isolation enforced +- Security best practices followed + +### Phase 6: Polish & Deployment + +#### Task 6.1: Error Handling & User Experience +**Status:** ⏳ Not Started + +**Description:** Improve error handling and user experience. + +**Subtasks:** +- [ ] Add retry logic for transient failures +- [ ] Improve error messages (user-friendly) +- [ ] Add loading indicators +- [ ] Add connection status indicators +- [ ] Implement graceful degradation +- [ ] Add telemetry/logging (optional) + +**Acceptance Criteria:** +- Users receive clear feedback +- System handles errors gracefully +- UX is polished and professional + +#### Task 6.2: Example Repository Structure +**Status:** ⏳ Not Started + +**Description:** Organize the example code in the repository. + +**Structure:** +``` +bridge-examples/ + office/ + readme.md (this file) + bridge-local/ + package.json + src/ + index.ts + .env.example + README.md + gateway-server/ + package.json + src/ + index.ts + discovery.ts + auth.ts + config.ts + .env.example + README.md + web-app/ + package.json + src/ + App.tsx + components/ + EmailForm.tsx + config.ts + docs/ + architecture.md + setup-sso.md + troubleshooting.md + scripts/ + install-outlook.ps1 + setup-gateway.ps1 + start-all.ps1 +``` + +**Acceptance Criteria:** +- Code is well-organized +- Easy to navigate +- Follows repository conventions + +## Prerequisites + +- Windows 10/11 +- Microsoft Outlook (2016 or later) +- Node.js (v18 or later) +- io.Bridge license key +- (Optional) SSO provider account (Auth0 or similar) for authentication demo + +**Note:** This example runs io.Bridge locally using the `@interopio/bridge` package. No cluster deployment is required. + +## Quick Start + +_(To be completed after implementation)_ + +## Configuration + +### SSO Provider + +_(To be completed based on chosen provider)_ + +### Gateway Server + +_(To be completed)_ + +### Browser App + +_(To be completed)_ + +## Troubleshooting + +_(To be completed)_ + +## License + +_(To be defined)_ + +## Contributing + +_(To be defined)_ diff --git a/office/src/App.css b/office/src/App.css new file mode 100644 index 0000000..0ae7210 --- /dev/null +++ b/office/src/App.css @@ -0,0 +1,264 @@ +:root { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; + line-height: 1.5; + font-weight: 400; + color: #213547; + background-color: #f5f5f5; +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + margin: 0; + display: flex; + min-width: 320px; + min-height: 100vh; +} + +#root { + width: 100%; +} + +.app { + max-width: 1200px; + margin: 0 auto; + padding: 2rem; + min-height: 100vh; + display: flex; + flex-direction: column; +} + +header { + margin-bottom: 2rem; + padding-bottom: 1rem; + border-bottom: 2px solid #e0e0e0; +} + +header h1 { + font-size: 2rem; + margin-bottom: 0.5rem; + color: #0078d4; +} + +.status { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 0.9rem; + color: #666; +} + +.indicator { + width: 10px; + height: 10px; + border-radius: 50%; + display: inline-block; +} + +.indicator.connected { + background-color: #28a745; + box-shadow: 0 0 4px #28a745; +} + +.indicator.disconnected { + background-color: #dc3545; +} + +main { + flex: 1; +} + +footer { + margin-top: 2rem; + padding-top: 1rem; + border-top: 1px solid #e0e0e0; + text-align: center; + color: #666; + font-size: 0.9rem; +} + +.app.loading, +.app.error { + display: flex; + justify-content: center; + align-items: center; + text-align: center; +} + +.app.error h1 { + color: #dc3545; + margin-bottom: 1rem; +} + +.app.error button { + margin-top: 1rem; + padding: 0.5rem 1rem; + background-color: #0078d4; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 1rem; +} + +.app.error button:hover { + background-color: #005a9e; +} + +button { + font-family: inherit; +} + +/* Outlook Child App Styles */ +.outlook-container { + max-width: 800px; + margin: 0 auto; + padding: 2rem; + min-height: 100vh; + display: flex; + flex-direction: column; +} + +.outlook-header { + margin-bottom: 2rem; + padding-bottom: 1rem; + border-bottom: 2px solid #e0e0e0; +} + +.outlook-header h1 { + font-size: 1.75rem; + margin-bottom: 0.5rem; + color: #0078d4; +} + +.outlook-header p { + color: #666; + font-size: 0.95rem; +} + +.outlook-main { + flex: 1; +} + +.outlook-container .loading { + display: flex; + justify-content: center; + align-items: center; + height: 200px; + font-size: 1.1rem; + color: #666; +} + +.outlook-container .error { + background-color: #fff5f5; + border: 1px solid #dc3545; + border-radius: 8px; + padding: 1.5rem; + color: #dc3545; +} + +.outlook-container .error h2 { + margin-bottom: 0.5rem; +} + +/* Email Form Styles */ +.email-form { + background: white; + padding: 1.5rem; + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +.form-group { + margin-bottom: 1.25rem; +} + +.form-group label { + display: block; + font-weight: 500; + margin-bottom: 0.5rem; + color: #333; +} + +.form-group input, +.form-group textarea { + width: 100%; + padding: 0.75rem; + border: 1px solid #ccc; + border-radius: 4px; + font-size: 1rem; + font-family: inherit; + transition: border-color 0.2s, box-shadow 0.2s; +} + +.form-group input:focus, +.form-group textarea:focus { + outline: none; + border-color: #0078d4; + box-shadow: 0 0 0 3px rgba(0, 120, 212, 0.15); +} + +.form-group input:disabled, +.form-group textarea:disabled { + background-color: #f5f5f5; + cursor: not-allowed; +} + +.form-group textarea { + resize: vertical; + min-height: 150px; +} + +.form-actions { + margin-top: 1.5rem; +} + +.form-actions button { + width: 100%; + padding: 0.875rem 1.5rem; + background-color: #0078d4; + color: white; + border: none; + border-radius: 4px; + font-size: 1rem; + font-weight: 500; + cursor: pointer; + transition: background-color 0.2s; +} + +.form-actions button:hover:not(:disabled) { + background-color: #005a9e; +} + +.form-actions button:disabled { + opacity: 0.7; + cursor: not-allowed; +} + +.form-actions button.success { + background-color: #28a745; +} + +.error-message { + margin-top: 1rem; + padding: 0.75rem 1rem; + background-color: #fff5f5; + border: 1px solid #dc3545; + border-radius: 4px; + color: #dc3545; + font-size: 0.9rem; +} + +.success-message { + margin-top: 1rem; + padding: 0.75rem 1rem; + background-color: #f0fff4; + border: 1px solid #28a745; + border-radius: 4px; + color: #28a745; + font-size: 0.9rem; +} diff --git a/office/src/App.tsx b/office/src/App.tsx new file mode 100644 index 0000000..9b3b91c --- /dev/null +++ b/office/src/App.tsx @@ -0,0 +1,184 @@ +import IOBrowserPlatform from "@interopio/browser-platform"; +import { IOConnectHome, type UserData } from "@interopio/home-ui-react"; +import type { IOConnectInitSettings } from "@interopio/react-hooks"; +import IOModals from "@interopio/modals-api"; +import IOSearch from "@interopio/search-api"; +import IOWorkspaces from "@interopio/workspaces-api"; +import "@interopio/home-ui-react/index.css"; +import "@interopio/workspaces-ui-react/dist/styles/workspaces.css"; +import "./App.css"; +import config from "./config.json"; + +const appBaseUrl = new URL(import.meta.env.BASE_URL, window.location.origin); +const appBasePath = appBaseUrl.pathname; +const outlookAppUrl = new URL("outlook/", appBaseUrl).toString(); +const modalsBaseUrl = new URL("static/modals/", appBaseUrl); + +function requireNonEmptyString(value: string | undefined, name: string): string { + if (!value || value.trim() === "") { + throw new Error(`Environment variable ${name} is required and cannot be empty.`); + } + return value; +} + +const getConfig = (userData: UserData): IOConnectInitSettings => { + const bridgeUrl = import.meta.env.VITE_IO_BRIDGE_URL || "https://gw-bridge-examples.interop.io"; + const licenseKey = (userData.type === "auth0" ? userData.user["https://interop.io/io_cb_license_key"] as string : undefined) ?? import.meta.env.VITE_IO_CB_LICENSE_KEY as string; + + // Extract user details from login + const user = userData.user; + + // Platform configuration + return { + browserPlatform: { + factory: async (platformConfig) => { + const platformInit = await IOBrowserPlatform(platformConfig); + + (window as any).io = platformInit.io; + (window as any).platform = platformInit.platform; + + return platformInit; + }, + config: { + // License key from environment + licenseKey, + environment: config.environment, + applications: { + local: [ + { + name: "outlook-demo", + type: "window", + title: "Outlook Demo", + details: { + url: outlookAppUrl, + }, + customProperties: { + includeInWorkspaces: true + } + }, + { + name: "excel-playground", + type: "window", + "title": "Excel Playground", + details: { + url: 'https://interopio.github.io/excel-playground/' + } + }, + { + name: "excel-playground-local", + type: "window", + "title": "Excel Playground (Local)", + details: { + url: ' http://localhost:4173/' + } + } + ] + }, + layouts: { + mode: "idb" + }, + channels: { + definitions: config.channels + }, + browser: { + libraries: [IOWorkspaces, IOModals, IOSearch], + modals: { + dialogs: { + enabled: true + }, + alerts: { + enabled: true + } + }, + systemLogger: { + level: "debug" + }, + intentResolver: { + enable: true + } + }, + modals: { + sources: { + bundle: new URL("io-browser-modals-ui.es.js", modalsBaseUrl).toString(), + styles: [new URL("styles.css", modalsBaseUrl).toString()], + fonts: [new URL("fonts.css", modalsBaseUrl).toString()] + } + }, + + // Gateway configuration - connect to local io.Bridge + gateway: { + logging: { + level: 'warn', + appender: (info) => { + console.log(`[${info.namespace}]: ${info.message}`); + }, + }, + bridge: { + url: bridgeUrl, + search: { + enabled: true, + }, + interop: { + enabled: true, + visibility: [ + { + method: new RegExp(/[\s\S]*/), + restrictions: "cluster", + identity: { application: new RegExp(/(Outlook|IOXLAddin)/)} + }, + ] + }, + async getHeaders() { + const headers: Record = {}; + if (userData && userData.type === "auth0") { + headers["Authorization"] = `Bearer ${userData.user.token}`; + } + return headers; + }, + getWebSocketSearchParams() { + const params: Record = {}; + if (userData && userData.type === "auth0") { + params["access_token"] = `${userData.user.token}`; + } + return params; + } + } + }, + // User details required when connecting to io.Bridge + user: { + id: user?.id || 'anonymous', + username: user?.username || 'anonymous' + }, + // Workspaces App configuration + workspaces: { + src: appBasePath, + isFrame: true + } + } + } + }; +}; + +// Configuration for the IOConnectHome component +const homeConfig = { + getIOConnectConfig: getConfig, + // Simple login - no authentication required for this example + login: { + type: "auth0" as const, + providerOptions: { + domain: requireNonEmptyString(import.meta.env.VITE_AUTH0_DOMAIN, 'VITE_AUTH0_DOMAIN'), + clientId: requireNonEmptyString(import.meta.env.VITE_AUTH0_CLIENT_ID, 'VITE_AUTH0_CLIENT_ID'), + authorizationParams: { + audience: requireNonEmptyString(import.meta.env.VITE_AUTH0_AUDIENCE, 'VITE_AUTH0_AUDIENCE'), + scope: import.meta.env.VITE_AUTH0_SCOPE ?? 'openid profile email', + redirect_uri: appBaseUrl.toString(), + } + }, + } +}; + +function App() { + return ; +} + +export default App; diff --git a/office/src/config.json b/office/src/config.json new file mode 100644 index 0000000..1ea95a8 --- /dev/null +++ b/office/src/config.json @@ -0,0 +1,36 @@ +{ + "channels": [ + { + "name": "Red", + "meta": { + "color": "red", + "name": "Red", + "fdc3": { + "id": "fdc3.channel.1", + "displayMetadata": { + "name": "Channel 1", + "glyph": "1" + } + } + } + }, + { + "name": "Green", + "meta": { + "color": "green", + "name": "Green", + "fdc3": { + "id": "fdc3.channel.4", + "displayMetadata": { + "name": "Channel 4", + "glyph": "4" + } + } + } + } + ], + "environment": { + "environment": "DEMO", + "region": "INTEROP.IO" + } +} diff --git a/office/src/index.css b/office/src/index.css new file mode 100644 index 0000000..96ba8a3 --- /dev/null +++ b/office/src/index.css @@ -0,0 +1,5 @@ +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} diff --git a/office/src/index.html b/office/src/index.html new file mode 100644 index 0000000..3c81070 --- /dev/null +++ b/office/src/index.html @@ -0,0 +1,12 @@ + + + + + + io.Bridge Outlook Example + + +
+ + + diff --git a/office/src/main.tsx b/office/src/main.tsx new file mode 100644 index 0000000..ee5fac2 --- /dev/null +++ b/office/src/main.tsx @@ -0,0 +1,7 @@ +import ReactDOM from 'react-dom/client'; +import App from './App'; +import './index.css'; + +ReactDOM.createRoot(document.getElementById('root')!).render( + +); diff --git a/office/src/outlook/OutlookApp.tsx b/office/src/outlook/OutlookApp.tsx new file mode 100644 index 0000000..9354db4 --- /dev/null +++ b/office/src/outlook/OutlookApp.tsx @@ -0,0 +1,92 @@ +import { useState, useEffect } from 'react'; +import { useIOConnect } from '@interopio/react-hooks'; +import EmailForm from './components/EmailForm'; +import '../App.css'; + +function getBrowserInfo(): string { + const ua = navigator.userAgent; + let browser = 'Unknown Browser'; + let version = ''; + + if (ua.includes('Firefox/')) { + browser = 'Firefox'; + version = ua.match(/Firefox\/([\d.]+)/)?.[1] || ''; + } else if (ua.includes('Edg/')) { + browser = 'Microsoft Edge'; + version = ua.match(/Edg\/([\d.]+)/)?.[1] || ''; + } else if (ua.includes('Chrome/')) { + browser = 'Chrome'; + version = ua.match(/Chrome\/([\d.]+)/)?.[1] || ''; + } else if (ua.includes('Safari/')) { + browser = 'Safari'; + version = ua.match(/Version\/([\d.]+)/)?.[1] || ''; + } + + return `${browser} ${version}`; +} + +function OutlookApp() { + // io is initialized by the provider and exposed via react-hooks helper + const io = useIOConnect((initializedIO) => initializedIO); + const [initialBody, setInitialBody] = useState(null); + + useEffect(() => { + if (!io) return; + + const loadProfileData = async () => { + const browserInfo = getBrowserInfo(); + + try { + // system.getProfileData is available in Browser platform + const system = (io as any).system; + if (system && typeof system.getProfileData === 'function') { + const profileData = await system.getProfileData(); + const platformVersion = profileData.productsInfo?.platform?.apiVersion || io.version; + + setInitialBody( + `This message is prepared from ${browserInfo} using io.Connect ${platformVersion} via Outlook.` + ); + } else { + // Fallback for Desktop or older versions + setInitialBody( + `This message is prepared from ${browserInfo} using io.Connect ${io.version} via Outlook.` + ); + } + } catch (err) { + // Fallback to io.version if getProfileData fails + setInitialBody( + `This message is prepared from ${browserInfo} using io.Connect ${io.version} via Outlook.` + ); + } + }; + + loadProfileData(); + }, [io]); + + if (!io || initialBody === null) { + return ( +
+
Connecting to io.Connect...
+
+ ); + } + + + return ( +
+
+

📧 Outlook Email Demo

+

Send emails via io.Bridge to Outlook

+
+
+ +
+
+ ); +} + +export default OutlookApp; diff --git a/office/src/outlook/components/EmailForm.tsx b/office/src/outlook/components/EmailForm.tsx new file mode 100644 index 0000000..1c9e21b --- /dev/null +++ b/office/src/outlook/components/EmailForm.tsx @@ -0,0 +1,209 @@ +import { useState, useEffect, useCallback } from 'react'; +import type { SyntheticEvent, ChangeEvent } from 'react'; +import type { IOConnectBrowser } from '@interopio/browser'; +import type { IOConnectDesktop } from '@interopio/desktop'; + +type IOApi = IOConnectBrowser.API | IOConnectDesktop.API; + +const OUTLOOK_METHOD = 'T42.Outlook.CreateEmail'; + +interface EmailFormProps { + io: IOApi; + initialSubject?: string; + initialBody?: string; +} + +interface EmailData { + to: string; + subject: string; + body: string; +} + +interface OutlookServerInfo { + available: boolean; + machine?: string; + application?: string; +} + +type SendStatus = 'idle' | 'sending' | 'success' | 'error'; + +export default function EmailForm({ io, initialSubject = '', initialBody = '' }: EmailFormProps) { + const [email, setEmail] = useState({ + to: '', + subject: initialSubject, + body: initialBody + }); + + const [outlookServer, setOutlookServer] = useState({ available: false }); + + // Check if the Outlook method is available and track server info + const updateOutlookMethodStatus = useCallback(() => { + const methods = io.interop.methods({ name: OUTLOOK_METHOD }); + if (methods.length > 0) { + // Get the first server that provides this method + const servers = methods[0].getServers?.() || []; + if (servers.length > 0) { + const server = servers[0]; + setOutlookServer({ + available: true, + machine: server.machine, + application: server.application + }); + return; + } + } + setOutlookServer({ available: false }); + }, [io]); + + useEffect(() => { + // Check initial state + updateOutlookMethodStatus(); + + // Subscribe to method added/removed events + const unsubAdded = io.interop.serverMethodAdded(({ method }) => { + if (method.name === OUTLOOK_METHOD) { + updateOutlookMethodStatus(); + } + }); + + const unsubRemoved = io.interop.serverMethodRemoved(({ method }) => { + if (method.name === OUTLOOK_METHOD) { + updateOutlookMethodStatus(); + } + }); + + return () => { + unsubAdded(); + unsubRemoved(); + }; + }, [io, updateOutlookMethodStatus]); + + // Sync initial values when props change (e.g., when initialBody is loaded async) + useEffect(() => { + setEmail(prev => ({ + ...prev, + subject: initialSubject, + body: initialBody + })); + }, [initialSubject, initialBody]); + const [status, setStatus] = useState('idle'); + const [errorMessage, setErrorMessage] = useState(''); + + const handleSubmit = async (e: SyntheticEvent) => { + e.preventDefault(); + setStatus('sending'); + setErrorMessage(''); + + try { + // Invoke the Outlook add-on's email method via interop + // T42.SendEmail accepts: To, Subject, Body, HTMLBody, Cc, Bcc, AttachFiles, SendFrom + await io.interop.invoke(OUTLOOK_METHOD, { + To: [email.to], + Subject: email.subject, + Body: email.body + }); + + setStatus('success'); + // Reset form after success + setTimeout(() => { + setEmail({ to: '', subject: initialSubject, body: initialBody }); + setStatus('idle'); + }, 3000); + } catch (err) { + setStatus('error'); + setErrorMessage(err instanceof Error ? err.message : 'Unknown error occurred'); + } + }; + + const handleChange = (field: keyof EmailData) => ( + e: ChangeEvent + ) => { + setEmail(prev => ({ ...prev, [field]: e.target.value })); + if (status === 'error') { + setStatus('idle'); + setErrorMessage(''); + } + }; + + return ( +
+
+ + +
+ +
+ + +
+ +
+ +