diff --git a/webapp/_webapp/bun.lock b/webapp/_webapp/bun.lock index 7667686..c4d2448 100644 --- a/webapp/_webapp/bun.lock +++ b/webapp/_webapp/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "webapp", @@ -12,6 +13,7 @@ "@heroui/react": "^2.7.9", "@iconify/react": "^6.0.0", "@lukemorales/query-key-factory": "^1.3.4", + "@r2wc/react-to-web-component": "^2.1.0", "@tanstack/react-query": "^5.79.0", "@types/diff": "^8.0.0", "@uidotdev/usehooks": "^2.4.1", @@ -415,6 +417,10 @@ "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="], + "@r2wc/core": ["@r2wc/core@1.3.0", "", {}, "sha512-aPBnND92Itl+SWWbWyyxdFFF0+RqKB6dptGHEdiPB8ZvnHWHlVzOfEvbEcyUYGtB6HBdsfkVuBiaGYyBFVTzVQ=="], + + "@r2wc/react-to-web-component": ["@r2wc/react-to-web-component@2.1.0", "", { "dependencies": { "@r2wc/core": "^1.3.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-m/PzgUOEiL1HxmvfP5LgBLqB7sHeRj+d1QAeZklwS4OEI2HUU+xTpT3hhJipH5DQoFInDqDTfe0lNFFKcrqk4w=="], + "@react-aria/breadcrumbs": ["@react-aria/breadcrumbs@3.5.24", "", { "dependencies": { "@react-aria/i18n": "^3.12.9", "@react-aria/link": "^3.8.1", "@react-aria/utils": "^3.29.0", "@react-types/breadcrumbs": "^3.7.13", "@react-types/shared": "^3.29.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-CRheGyyM8afPJvDHLXn/mmGG/WAr/z2LReK3DlPdxVKcsOn7g3NIRxAcAIAJQlDLdOiu1SXHiZe6uu2jPhHrxA=="], "@react-aria/button": ["@react-aria/button@3.13.1", "", { "dependencies": { "@react-aria/interactions": "^3.25.1", "@react-aria/toolbar": "3.0.0-beta.16", "@react-aria/utils": "^3.29.0", "@react-stately/toggle": "^3.8.4", "@react-types/button": "^3.12.1", "@react-types/shared": "^3.29.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-E49qcbBRgofXYfWbli50bepWVNtQBq7qewL9XsX7nHkwPPUe1IRwJOnWZqYMgwwhUBOXfnsR6/TssiXqZsrJdw=="], diff --git a/webapp/_webapp/package-lock.json b/webapp/_webapp/package-lock.json index 595bf82..aefcb68 100644 --- a/webapp/_webapp/package-lock.json +++ b/webapp/_webapp/package-lock.json @@ -11,9 +11,12 @@ "@buf/googleapis_googleapis.bufbuild_es": "^2.2.3-20250211200939-546238c53f73.1", "@bufbuild/protobuf": "^2.5.1", "@capacitor-community/apple-sign-in": "^7.0.1", + "@grafana/faro-web-sdk": "^2.0.2", + "@grafana/faro-web-tracing": "^2.0.2", "@heroui/react": "^2.7.9", "@iconify/react": "^6.0.0", "@lukemorales/query-key-factory": "^1.3.4", + "@r2wc/react-to-web-component": "^2.1.0", "@tanstack/react-query": "^5.79.0", "@types/diff": "^8.0.0", "@uidotdev/usehooks": "^2.4.1", @@ -38,6 +41,7 @@ "@codemirror/state": "^6.5.2", "@codemirror/view": "^6.37.1", "@eslint/js": "^9.28.0", + "@grafana/faro-rollup-plugin": "^0.7.0", "@types/chrome": "^0.0.326", "@types/codemirror": "^5.60.16", "@types/events": "^3.0.3", @@ -91,7 +95,8 @@ "version": "2.5.1", "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.5.1.tgz", "integrity": "sha512-lut4UTvKL8tqtend0UDu7R79/n9jA7Jtxf77RNPbxtmWqfWI4qQ9bTjf7KCS4vfqLmpQbuHr1ciqJumAgJODdw==", - "license": "(Apache-2.0 AND BSD-3-Clause)" + "license": "(Apache-2.0 AND BSD-3-Clause)", + "peer": true }, "node_modules/@capacitor-community/apple-sign-in": { "version": "7.0.1", @@ -782,6 +787,70 @@ "tslib": "^2.8.0" } }, + "node_modules/@grafana/faro-bundlers-shared": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@grafana/faro-bundlers-shared/-/faro-bundlers-shared-0.7.0.tgz", + "integrity": "sha512-wNc9ktcZK4CwRmQ/FRB/SbI4ThnkaekGOQuPq6r/Oz+urDjrUpjjZ3cC+KpP47OcWYAuLaIisrt092mZ/Rm+6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "ansis": "^4.0.0", + "tar": "^7.1.0" + } + }, + "node_modules/@grafana/faro-core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@grafana/faro-core/-/faro-core-2.1.0.tgz", + "integrity": "sha512-Pc9U2gWH8I1AVeXKLK667NF8N3Nwa1AcAAV3/KKG7C0ZDoy6kY5lXOMY930lzqFtuaji0B2tidayYxrfDmicXA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/otlp-transformer": "^0.208.0" + } + }, + "node_modules/@grafana/faro-rollup-plugin": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@grafana/faro-rollup-plugin/-/faro-rollup-plugin-0.7.1.tgz", + "integrity": "sha512-+Z6wyqJw5HX6OSktgDxTjGQ+pdx6vsT70mbBX24k95kHV0xbefMt7MSHxJ+NIarLy0SQSTnaIofUhiR47L7lUQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@grafana/faro-bundlers-shared": "^0.7.0", + "cross-fetch": "^4.0.0", + "magic-string": "^0.30.5", + "rollup": "^4.22.4" + } + }, + "node_modules/@grafana/faro-web-sdk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@grafana/faro-web-sdk/-/faro-web-sdk-2.1.0.tgz", + "integrity": "sha512-ozutA3rN1h+JLphXGOz3B0jb81ew0lBHJEXg47EvWozyZtwtsMWTAX+4PP63Sm5P/BMO/Jm3rt3LtOORXnsPPg==", + "license": "Apache-2.0", + "dependencies": { + "@grafana/faro-core": "^2.1.0", + "ua-parser-js": "^1.0.32", + "web-vitals": "^5.0.3" + } + }, + "node_modules/@grafana/faro-web-tracing": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@grafana/faro-web-tracing/-/faro-web-tracing-2.1.0.tgz", + "integrity": "sha512-S8Pkq+mU2LjRuyzbRvY2eSFJn3i9cJTN7dzmiv0CQJHEpzFcCMsTEdY4UhrdO3moPIF5qipl3RJvb6fCfOaDLw==", + "license": "Apache-2.0", + "dependencies": { + "@grafana/faro-web-sdk": "^2.1.0", + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.208.0", + "@opentelemetry/instrumentation": "^0.208.0", + "@opentelemetry/instrumentation-fetch": "^0.208.0", + "@opentelemetry/instrumentation-xml-http-request": "^0.208.0", + "@opentelemetry/otlp-transformer": "^0.208.0", + "@opentelemetry/resources": "^2.0.0", + "@opentelemetry/sdk-trace-web": "^2.0.0", + "@opentelemetry/semantic-conventions": "^1.32.0" + } + }, "node_modules/@heroui/accordion": { "version": "2.2.17", "resolved": "https://registry.npmjs.org/@heroui/accordion/-/accordion-2.2.17.tgz", @@ -1908,6 +1977,7 @@ "resolved": "https://registry.npmjs.org/@heroui/system/-/system-2.4.16.tgz", "integrity": "sha512-kk8XQsejHv4/vZBm7936D9+YkKV/meUp2tY49auS0wLsrGOQ2vvBKiwzQ0r+ibTvSNyCe5SX9tLfEGVgaGIY7g==", "license": "MIT", + "peer": true, "dependencies": { "@heroui/react-utils": "2.1.10", "@heroui/system-rsc": "2.3.14", @@ -2001,6 +2071,7 @@ "resolved": "https://registry.npmjs.org/@heroui/theme/-/theme-2.4.16.tgz", "integrity": "sha512-XWRr1MJNBGIESxOCgPgQMq3gt8VfWoYzDnBpIdIHjSlin+4oK8LRqLsP6CeVTpGSwv6lurQk11jVKY6MTI7JTw==", "license": "MIT", + "peer": true, "dependencies": { "@heroui/shared-utils": "2.1.9", "clsx": "^1.2.1", @@ -2479,6 +2550,19 @@ "node": ">=12" } }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", @@ -2512,9 +2596,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "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": { @@ -2582,6 +2666,243 @@ "node": ">= 8" } }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.208.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.208.0.tgz", + "integrity": "sha512-CjruKY9V6NMssL/T1kAFgzosF1v9o6oeN+aX5JB/C/xPNtmgIJqcXHG7fA82Ou1zCpWGl4lROQUKwUNE1pMCyg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.2.0.tgz", + "integrity": "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http": { + "version": "0.208.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.208.0.tgz", + "integrity": "sha512-jbzDw1q+BkwKFq9yxhjAJ9rjKldbt5AgIy1gmEIJjEV/WRxQ3B6HcLVkwbjJ3RcMif86BDNKR846KJ0tY0aOJA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/otlp-exporter-base": "0.208.0", + "@opentelemetry/otlp-transformer": "0.208.0", + "@opentelemetry/resources": "2.2.0", + "@opentelemetry/sdk-trace-base": "2.2.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.208.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.208.0.tgz", + "integrity": "sha512-Eju0L4qWcQS+oXxi6pgh7zvE2byogAkcsVv0OjHF/97iOz1N/aKE6etSGowYkie+YA1uo6DNwdSxaaNnLvcRlA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.208.0", + "import-in-the-middle": "^2.0.0", + "require-in-the-middle": "^8.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fetch": { + "version": "0.208.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fetch/-/instrumentation-fetch-0.208.0.tgz", + "integrity": "sha512-zgStoUfNF1xH9bCq539k1aeieKxPiAvBo5gKipQ9fIt+eJsFvqGcSzrrDX+OYgpIPW/IVNgWBoOw6zVmKwgNwQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/instrumentation": "0.208.0", + "@opentelemetry/sdk-trace-web": "2.2.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-xml-http-request": { + "version": "0.208.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-xml-http-request/-/instrumentation-xml-http-request-0.208.0.tgz", + "integrity": "sha512-me0knebxJxnzis73p5/ZQgdLNG6nsUXMsDR/dZk+BPOiNyd3Me9ye2wVM06JlcLA54w4JESw6wMTNi4lMhowFQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/instrumentation": "0.208.0", + "@opentelemetry/sdk-trace-web": "2.2.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.208.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.208.0.tgz", + "integrity": "sha512-gMd39gIfVb2OgxldxUtOwGJYSH8P1kVFFlJLuut32L6KgUC4gl1dMhn+YC2mGn0bDOiQYSk/uHOdSjuKp58vvA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/otlp-transformer": "0.208.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer": { + "version": "0.208.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.208.0.tgz", + "integrity": "sha512-DCFPY8C6lAQHUNkzcNT9R+qYExvsk6C5Bto2pbNxgicpcSWbe2WHShLxkOxIdNcBiYPdVHv/e7vH7K6TI+C+fQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.208.0", + "@opentelemetry/core": "2.2.0", + "@opentelemetry/resources": "2.2.0", + "@opentelemetry/sdk-logs": "0.208.0", + "@opentelemetry/sdk-metrics": "2.2.0", + "@opentelemetry/sdk-trace-base": "2.2.0", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", + "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs": { + "version": "0.208.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.208.0.tgz", + "integrity": "sha512-QlAyL1jRpOeaqx7/leG1vJMp84g0xKP6gJmfELBpnI4O/9xPX+Hu5m1POk9Kl+veNkyth5t19hRlN6tNY1sjbA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.208.0", + "@opentelemetry/core": "2.2.0", + "@opentelemetry/resources": "2.2.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.2.0.tgz", + "integrity": "sha512-G5KYP6+VJMZzpGipQw7Giif48h6SGQ2PFKEYCybeXJsOCB4fp8azqMAAzE5lnnHK3ZVwYQrgmFbsUJO/zOnwGw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/resources": "2.2.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.2.0.tgz", + "integrity": "sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/resources": "2.2.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-web": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-web/-/sdk-trace-web-2.2.0.tgz", + "integrity": "sha512-x/LHsDBO3kfqaFx5qSzBljJ5QHsRXrvS4MybBDy1k7Svidb8ZyIPudWVzj3s5LpPkYZIgi9e+7tdsNCnptoelw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/sdk-trace-base": "2.2.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.38.0.tgz", + "integrity": "sha512-kocjix+/sSggfJhwXqClZ3i9Y/MI0fp7b+g7kCRm6psy2dsf8uApTRclwG18h8Avm7C9+fnt+O36PspJ/OzoWg==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -2592,6 +2913,89 @@ "node": ">=14" } }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, + "node_modules/@r2wc/core": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@r2wc/core/-/core-1.3.0.tgz", + "integrity": "sha512-aPBnND92Itl+SWWbWyyxdFFF0+RqKB6dptGHEdiPB8ZvnHWHlVzOfEvbEcyUYGtB6HBdsfkVuBiaGYyBFVTzVQ==", + "license": "MIT" + }, + "node_modules/@r2wc/react-to-web-component": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@r2wc/react-to-web-component/-/react-to-web-component-2.1.0.tgz", + "integrity": "sha512-m/PzgUOEiL1HxmvfP5LgBLqB7sHeRj+d1QAeZklwS4OEI2HUU+xTpT3hhJipH5DQoFInDqDTfe0lNFFKcrqk4w==", + "license": "MIT", + "dependencies": { + "@r2wc/core": "^1.3.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, "node_modules/@react-aria/breadcrumbs": { "version": "3.5.24", "resolved": "https://registry.npmjs.org/@react-aria/breadcrumbs/-/breadcrumbs-3.5.24.tgz", @@ -4517,6 +4921,7 @@ "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.79.0.tgz", "integrity": "sha512-s+epTqqLM0/TbJzMAK7OEhZIzh63P9sWz5HEFc5XHL4FvKQXQkcjI8F3nee+H/xVVn7mrP610nVXwOytTSYd0w==", "license": "MIT", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" @@ -4527,6 +4932,7 @@ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.79.0.tgz", "integrity": "sha512-DjC4JIYZnYzxaTzbg3osOU63VNLP67dOrWet2cZvXgmgwAXNxfS52AMq86M5++ILuzW+BqTUEVMTjhrZ7/XBuA==", "license": "MIT", + "peer": true, "dependencies": { "@tanstack/query-core": "5.79.0" }, @@ -4660,7 +5066,6 @@ "version": "22.15.29", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.29.tgz", "integrity": "sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -4672,6 +5077,7 @@ "integrity": "sha512-JeG0rEWak0N6Itr6QUx+X60uQmN+5t3j9r/OVDtWzFXKaj6kD1BwJzOksD0FF6iWxZlbE1kB0q9vtnU2ekqa1Q==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -4755,6 +5161,7 @@ "integrity": "sha512-JaehZvf6m0yqYp34+RVnihBAChkqeH+tqqhS0GuX1qgPpwLvmTPheKEs6OeCK6hVJgXZHJ2vbjnC9j119auStQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.33.0", "@typescript-eslint/types": "8.33.0", @@ -4994,8 +5401,8 @@ "version": "8.14.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", - "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5003,6 +5410,15 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -5057,6 +5473,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/ansis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.2.0.tgz", + "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -5205,6 +5631,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001718", "electron-to-chromium": "^1.5.160", @@ -5324,6 +5751,22 @@ "node": ">= 6" } }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "license": "MIT" + }, "node_modules/clsx": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", @@ -5427,6 +5870,16 @@ "dev": true, "license": "MIT" }, + "node_modules/cross-fetch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", + "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -5464,7 +5917,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -5678,6 +6130,7 @@ "integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -6060,6 +6513,7 @@ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.15.0.tgz", "integrity": "sha512-XKg/LnKExdLGugZrDILV7jZjI599785lDIJZLxMiiIFidCsy0a4R2ZEf+Izm67zyOuJgQYTHOmodi7igQsw3vg==", "license": "MIT", + "peer": true, "dependencies": { "motion-dom": "^12.15.0", "motion-utils": "^12.12.1", @@ -6316,6 +6770,7 @@ "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -6338,6 +6793,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-in-the-middle": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-2.0.1.tgz", + "integrity": "sha512-bruMpJ7xz+9jwGzrwEhWgvRrlKRYCRDBrfU+ur3FcasYXLJDxTruJ//8g2Noj+QFyRBeqbpj8Bhn4Fbw6HjvhA==", + "license": "Apache-2.0", + "dependencies": { + "acorn": "^8.14.0", + "acorn-import-attributes": "^1.9.5", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -6610,6 +7077,12 @@ "dev": true, "license": "MIT" }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -6628,6 +7101,16 @@ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "license": "ISC" }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/markdown-to-jsx": { "version": "7.7.6", "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.7.6.tgz", @@ -6714,6 +7197,25 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/module-details-from-path": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", + "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", + "license": "MIT" + }, "node_modules/motion-dom": { "version": "12.15.0", "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.15.0.tgz", @@ -6733,7 +7235,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/mz": { @@ -6772,6 +7273,27 @@ "dev": true, "license": "MIT" }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-releases": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", @@ -7060,6 +7582,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -7227,6 +7750,30 @@ "react-is": "^16.13.1" } }, + "node_modules/protobufjs": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", + "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -7285,6 +7832,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -7294,6 +7842,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.26.0" }, @@ -7395,6 +7944,19 @@ "node": ">=8.10.0" } }, + "node_modules/require-in-the-middle": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-8.0.1.tgz", + "integrity": "sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "module-details-from-path": "^1.0.3" + }, + "engines": { + "node": ">=9.3.0 || >=8.10.0 <9.0.0" + } + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -7842,6 +8404,23 @@ "node": ">=14.0.0" } }, + "node_modules/tar": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz", + "integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -7901,6 +8480,7 @@ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -7930,6 +8510,13 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, "node_modules/ts-api-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", @@ -7974,6 +8561,7 @@ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -8005,6 +8593,32 @@ "typescript": ">=4.8.4 <5.9.0" } }, + "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/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", @@ -8016,7 +8630,6 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, "license": "MIT" }, "node_modules/update-browserslist-db": { @@ -8139,6 +8752,7 @@ "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -8229,6 +8843,7 @@ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -8243,6 +8858,30 @@ "dev": true, "license": "MIT" }, + "node_modules/web-vitals": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-5.1.0.tgz", + "integrity": "sha512-ArI3kx5jI0atlTtmV0fWU3fjpLmq/nD3Zr1iFFlJLaqa5wLBkUSzINwBPySCX/8jRyjlmy1Volw1kz1g9XE4Jg==", + "license": "Apache-2.0" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -8356,6 +8995,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/yaml": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", diff --git a/webapp/_webapp/package.json b/webapp/_webapp/package.json index 1b5a2e0..faf1f0a 100644 --- a/webapp/_webapp/package.json +++ b/webapp/_webapp/package.json @@ -9,6 +9,7 @@ "build": "tsc -b && npm run _build:default && npm run _build:background && npm run _build:intermediate && npm run _build:settings && npm run _build:popup", "_build": "vite build", "_build:default": "VITE_CONFIG=default npm run _build", + "_build:office": "VITE_CONFIG=office npm run _build", "_build:background": "VITE_CONFIG=background npm run _build", "_build:intermediate": "VITE_CONFIG=intermediate npm run _build", "_build:settings": "VITE_CONFIG=settings npm run _build", @@ -29,6 +30,7 @@ "@heroui/react": "^2.7.9", "@iconify/react": "^6.0.0", "@lukemorales/query-key-factory": "^1.3.4", + "@r2wc/react-to-web-component": "^2.1.0", "@tanstack/react-query": "^5.79.0", "@types/diff": "^8.0.0", "@uidotdev/usehooks": "^2.4.1", diff --git a/webapp/_webapp/src/adapters/context.tsx b/webapp/_webapp/src/adapters/context.tsx new file mode 100644 index 0000000..74abe0d --- /dev/null +++ b/webapp/_webapp/src/adapters/context.tsx @@ -0,0 +1,40 @@ +/** + * Adapter Context + * + * Provides the DocumentAdapter to React components via context. + * This allows UI components to access document operations without knowing the platform. + */ + +import { createContext, useContext, type ReactNode } from "react"; +import type { DocumentAdapter } from "./types"; + +const AdapterContext = createContext(null); + +interface AdapterProviderProps { + adapter: DocumentAdapter; + children: ReactNode; +} + +export function AdapterProvider({ adapter, children }: AdapterProviderProps) { + return {children}; +} + +/** + * Hook to access the document adapter + * @throws Error if used outside of AdapterProvider + */ +export function useAdapter(): DocumentAdapter { + const adapter = useContext(AdapterContext); + if (!adapter) { + throw new Error("useAdapter must be used within an AdapterProvider"); + } + return adapter; +} + +/** + * Hook to safely access the document adapter (returns null if not available) + */ +export function useAdapterOptional(): DocumentAdapter | null { + return useContext(AdapterContext); +} + diff --git a/webapp/_webapp/src/adapters/document-adapter.ts b/webapp/_webapp/src/adapters/document-adapter.ts new file mode 100644 index 0000000..09ef158 --- /dev/null +++ b/webapp/_webapp/src/adapters/document-adapter.ts @@ -0,0 +1,141 @@ +/** + * OverleafAdapter + * + * Document adapter implementation for Overleaf/browser environment. + * Uses CodeMirror editor APIs to interact with the document. + */ + +import { EditorView } from "@codemirror/view"; +import type { DocumentAdapter, SelectionInfo } from "./types"; +import { getCodeMirrorView, getProjectId } from "../libs/helpers"; + +export class OverleafAdapter implements DocumentAdapter { + readonly platform = "overleaf" as const; + + private getEditorView(): EditorView | null { + return getCodeMirrorView(); + } + + isReady(): boolean { + return this.getEditorView() !== null; + } + + async getFullText(): Promise { + const view = this.getEditorView(); + if (!view) { + return ""; + } + return view.state.doc.toString(); + } + + async getSelection(): Promise { + const view = this.getEditorView(); + if (!view) { + return null; + } + + const selection = view.state.selection.main; + if (selection.empty) { + return null; + } + + const text = view.state.sliceDoc(selection.from, selection.to); + const doc = view.state.doc; + + // Get surrounding context + const contextBefore = doc.sliceString(Math.max(0, selection.from - 100), selection.from); + const contextAfter = doc.sliceString(selection.to, Math.min(doc.length, selection.to + 100)); + const surroundingText = `${contextBefore}[SELECTED_TEXT_START]${text}[SELECTED_TEXT_END]${contextAfter}`; + + // Create a range identifier that can be used later + const rangeId = JSON.stringify({ from: selection.from, to: selection.to }); + + return { + text, + surroundingText, + rangeId, + }; + } + + async insertText(text: string, location: "cursor" | "start" | "end" = "cursor"): Promise { + const view = this.getEditorView(); + if (!view) { + throw new Error("Editor not available"); + } + + let pos: number; + switch (location) { + case "start": + pos = 0; + break; + case "end": + pos = view.state.doc.length; + break; + case "cursor": + default: + pos = view.state.selection.main.head; + break; + } + + view.dispatch({ + changes: { from: pos, insert: text }, + selection: { anchor: pos + text.length }, + }); + } + + async replaceSelection(text: string, rangeId?: string): Promise { + const view = this.getEditorView(); + if (!view) { + throw new Error("Editor not available"); + } + + let from: number; + let to: number; + + if (rangeId) { + try { + const range = JSON.parse(rangeId); + from = range.from; + to = range.to; + } catch { + // If rangeId is invalid, use current selection + from = view.state.selection.main.from; + to = view.state.selection.main.to; + } + } else { + from = view.state.selection.main.from; + to = view.state.selection.main.to; + } + + view.dispatch({ + changes: { from, to, insert: text }, + selection: { anchor: from + text.length }, + }); + } + + onSelectionChange(callback: (selection: SelectionInfo | null) => void): () => void { + const handler = () => { + this.getSelection().then(callback); + }; + + document.addEventListener("selectionchange", handler); + return () => { + document.removeEventListener("selectionchange", handler); + }; + } + + getDocumentId(): string { + return getProjectId(); + } +} + +// Singleton instance for browser environment +let overleafAdapterInstance: OverleafAdapter | null = null; + +export function getOverleafAdapter(): OverleafAdapter { + if (!overleafAdapterInstance) { + overleafAdapterInstance = new OverleafAdapter(); + } + return overleafAdapterInstance; +} + diff --git a/webapp/_webapp/src/adapters/index.ts b/webapp/_webapp/src/adapters/index.ts new file mode 100644 index 0000000..66fd071 --- /dev/null +++ b/webapp/_webapp/src/adapters/index.ts @@ -0,0 +1,29 @@ +/** + * Adapters module entry point + * + * Re-exports all adapter-related types, contexts, and implementations. + * + * Note: WordAdapter is NOT included here. It should be implemented and registered + * by the host application (e.g., Office Add-in) using the __pdRegisterAdapter() global function. + */ + +// Types +export type { + DocumentAdapter, + SelectionInfo, + AdapterProps, + StorageAdapter, +} from "./types"; + +// Context and hooks +export { AdapterProvider, useAdapter, useAdapterOptional } from "./context"; + +// Document Adapter Implementations +export { OverleafAdapter, getOverleafAdapter } from "./document-adapter"; + +// Storage Adapter Implementations +export { + LocalStorageAdapter, + MemoryStorageAdapter, + createStorageAdapter, +} from "./storage-adapter"; \ No newline at end of file diff --git a/webapp/_webapp/src/adapters/storage-adapter.ts b/webapp/_webapp/src/adapters/storage-adapter.ts new file mode 100644 index 0000000..a4a2da6 --- /dev/null +++ b/webapp/_webapp/src/adapters/storage-adapter.ts @@ -0,0 +1,102 @@ +/** + * Storage Adapter Implementations + * + * Browser-specific storage implementations for the webapp. + * - LocalStorageAdapter: Uses browser localStorage + * - MemoryStorageAdapter: In-memory fallback when localStorage is unavailable + */ + +import type { StorageAdapter } from "./types"; + +/** + * LocalStorage adapter for browser environments + */ +export class LocalStorageAdapter implements StorageAdapter { + getItem(key: string): string | null { + try { + return localStorage.getItem(key); + } catch { + console.warn("[Storage] localStorage.getItem failed for key:", key); + return null; + } + } + + setItem(key: string, value: string): void { + try { + localStorage.setItem(key, value); + } catch (e) { + console.warn("[Storage] localStorage.setItem failed for key:", key, e); + } + } + + removeItem(key: string): void { + try { + localStorage.removeItem(key); + } catch (e) { + console.warn("[Storage] localStorage.removeItem failed for key:", key, e); + } + } + + clear(): void { + try { + localStorage.clear(); + } catch (e) { + console.warn("[Storage] localStorage.clear failed", e); + } + } + + keys(): string[] { + try { + return Object.keys(localStorage); + } catch { + return []; + } + } +} + +/** + * In-memory storage adapter (fallback when no storage is available) + */ +export class MemoryStorageAdapter implements StorageAdapter { + private _store: Map = new Map(); + + getItem(key: string): string | null { + return this._store.get(key) ?? null; + } + + setItem(key: string, value: string): void { + this._store.set(key, value); + } + + removeItem(key: string): void { + this._store.delete(key); + } + + clear(): void { + this._store.clear(); + } + + keys(): string[] { + return Array.from(this._store.keys()); + } +} + +/** + * Create storage adapter for browser environment + */ +export function createStorageAdapter(type?: "localStorage" | "memory"): StorageAdapter { + if (type === "memory") { + return new MemoryStorageAdapter(); + } + + // Default: try localStorage, fallback to memory + try { + const testKey = "__storage_test__"; + localStorage.setItem(testKey, testKey); + localStorage.removeItem(testKey); + return new LocalStorageAdapter(); + } catch { + console.warn("[Storage] localStorage not available, falling back to memory storage"); + return new MemoryStorageAdapter(); + } +} diff --git a/webapp/_webapp/src/adapters/types.ts b/webapp/_webapp/src/adapters/types.ts new file mode 100644 index 0000000..9323ec6 --- /dev/null +++ b/webapp/_webapp/src/adapters/types.ts @@ -0,0 +1,103 @@ +/** + * Adapter Type Definitions + * + * Platform-agnostic interfaces for document and storage operations. + * + * ⚠️ SOURCE OF TRUTH - This file is synced to office-addin + * + * When modifying this file, run the sync script in office-addin: + * cd ../paperdebugger-office-addin && ./scripts/sync-types.sh + * + * Document Adapter Implementations: + * - OverleafAdapter: For Overleaf/browser environment (webapp) + * - WordAdapter: For Microsoft Word Office Add-in (office-addin) + * + * Storage Adapter Implementations: + * - LocalStorageAdapter: For browser localStorage (webapp) + * - MemoryStorageAdapter: For in-memory fallback (webapp) + * - OfficeRoamingAdapter: For Office roaming settings (office-addin) + * + * The React UI should only depend on these interfaces, never on platform-specific APIs. + */ + +// ============================================================================ +// Document Adapter Types +// ============================================================================ + +export interface SelectionInfo { + /** The selected text content */ + text: string; + /** Optional surrounding text for context (with markers like [SELECTED_TEXT_START] and [SELECTED_TEXT_END]) */ + surroundingText?: string; + /** Platform-specific range identifier for later operations */ + rangeId?: string; +} + +export interface DocumentAdapter { + /** + * Platform identifier for conditional UI rendering + */ + readonly platform: "overleaf" | "word" | "browser"; + + /** + * Get the full document text + */ + getFullText(): Promise; + + /** + * Get the currently selected text and its context + */ + getSelection(): Promise; + + /** + * Insert text at the current cursor position + * @param text - Text to insert + * @param location - Optional: 'cursor' (default), 'start', or 'end' + */ + insertText(text: string, location?: "cursor" | "start" | "end"): Promise; + + /** + * Replace the current selection with new text + * @param text - Text to replace with + * @param rangeId - Optional range identifier from getSelection() + */ + replaceSelection(text: string, rangeId?: string): Promise; + + /** + * Subscribe to selection change events + * @param callback - Called when selection changes + * @returns Cleanup function to unsubscribe + */ + onSelectionChange?(callback: (selection: SelectionInfo | null) => void): () => void; + + /** + * Check if the adapter is ready/connected + */ + isReady(): boolean; + + /** + * Optional: Get project/document identifier + */ + getDocumentId?(): string; +} + +/** + * Type for adapter props passed to Web Component + */ +export interface AdapterProps { + adapter?: DocumentAdapter; + displayMode?: "floating" | "bottom-fixed" | "right-fixed" | "fullscreen"; +} + +// ============================================================================ +// Storage Adapter Types +// ============================================================================ + +export interface StorageAdapter { + getItem(key: string): string | null; + setItem(key: string, value: string): void; + removeItem(key: string): void; + clear(): void; + /** Get all keys in storage */ + keys(): string[]; +} diff --git a/webapp/_webapp/src/components/text-patches.tsx b/webapp/_webapp/src/components/text-patches.tsx index e757424..615153b 100644 --- a/webapp/_webapp/src/components/text-patches.tsx +++ b/webapp/_webapp/src/components/text-patches.tsx @@ -1,10 +1,11 @@ import { Button } from "@heroui/react"; import { useCallback, useEffect, useRef, useState } from "react"; import { diffWords } from "diff"; -import { applyChanges, getProjectId } from "../libs/helpers"; +import { getProjectId } from "../libs/helpers"; import { useSelectionStore } from "../stores/selection-store"; import googleAnalytics from "../libs/google-analytics"; import { useAuthStore } from "../stores/auth-store"; +import { useAdapterOptional } from "../adapters"; type TextPatchesProps = { attachment?: string; @@ -15,6 +16,7 @@ type TextPatchesProps = { export function TextPatches({ attachment, children }: TextPatchesProps) { const { user } = useAuthStore(); const { selectionRange, setSelectionRange } = useSelectionStore(); + const adapter = useAdapterOptional(); const preRef = useRef(null); const [insertBtnText, setInsertBtnText] = useState("Insert"); @@ -32,16 +34,42 @@ export function TextPatches({ attachment, children }: TextPatchesProps) { } }, [preRef]); - const applyText = useCallback(() => { - if (preRef.current && selectionRange) { - applyChanges(preRef.current.innerText, selectionRange); - setSelectionRange(null); - setInsertBtnText("Applied!"); + const applyText = useCallback(async () => { + if (!preRef.current) return; + + const textToInsert = preRef.current.innerText; + + try { + // Prefer adapter-based insertion if available + if (adapter && adapter.isReady()) { + await adapter.replaceSelection(textToInsert); + setSelectionRange(null); + setInsertBtnText("Applied!"); + setTimeout(() => { + setInsertBtnText("Insert"); + }, 1500); + return; + } + + // Fallback to legacy Range-based insertion for Overleaf + if (selectionRange) { + const newText = document.createTextNode(textToInsert); + selectionRange.deleteContents(); + selectionRange.insertNode(newText); + setSelectionRange(null); + setInsertBtnText("Applied!"); + setTimeout(() => { + setInsertBtnText("Insert"); + }, 1500); + } + } catch (error) { + console.error("Failed to apply text:", error); + setInsertBtnText("Failed!"); setTimeout(() => { setInsertBtnText("Insert"); }, 1500); } - }, [preRef, selectionRange, setSelectionRange]); + }, [preRef, selectionRange, setSelectionRange, adapter]); // Process children to handle newlines let processedChildren = children; @@ -86,6 +114,11 @@ export function TextPatches({ attachment, children }: TextPatchesProps) { setMappedNodes(diffElements); }, [preRef, attachment]); + // Determine if insert button should be enabled + // With adapter: always enabled if adapter is ready + // Without adapter: only enabled if selectionRange exists (legacy Overleaf behavior) + const canInsert = (adapter && adapter.isReady()) || !!selectionRange; + return (
@@ -135,11 +168,11 @@ export function TextPatches({ attachment, children }: TextPatchesProps) {
         
-      
+      {!isWord && (
+        
+          
+
View onboarding guide
+
Learn how to use PaperDebugger effectively
+
+ +
+ )}
Status
@@ -47,21 +52,25 @@ export const AccountSettings = () => {
User
-
-
0 ? "bg-primary-500" : "bg-red-500", - )} - >
- Session -
-
-
0 ? "bg-primary-500" : "bg-red-500")} - >
- GCLB -
+ {!isWord && ( + <> +
+
0 ? "bg-primary-500" : "bg-red-500", + )} + >
+ Session +
+
+
0 ? "bg-primary-500" : "bg-red-500")} + >
+ GCLB +
+ + )}
diff --git a/webapp/_webapp/src/views/settings/sections/real-developer-tools.tsx b/webapp/_webapp/src/views/settings/sections/real-developer-tools.tsx index 8c6b79a..a9fbf0e 100644 --- a/webapp/_webapp/src/views/settings/sections/real-developer-tools.tsx +++ b/webapp/_webapp/src/views/settings/sections/real-developer-tools.tsx @@ -6,6 +6,14 @@ import { SettingsSectionContainer } from "./components"; import { SettingsSectionTitle } from "./components"; import { SettingItem } from "../setting-items"; import { localStorageKey, useDevtoolStore } from "../../../stores/devtool-store"; +import { storage } from "../../../libs/storage"; + +// Keys to preserve during reset +const PRESERVED_KEY_PREFIXES = [ + "pd.auth.", + "pd.devtool.", + "pd.projectId", +]; export const RealDeveloperTools = () => { const { @@ -77,9 +85,9 @@ export const RealDeveloperTools = () => { />
-
Reset localStorage and reload
+
Reset storage and reload
- Reset all user-configurable localStorage of the app except the:
+ Reset all user-configurable storage of the app except:
pd.projectId
pd.auth.* @@ -93,23 +101,36 @@ export const RealDeveloperTools = () => { color="secondary" radius="full" onPress={() => { - const refreshToken = localStorage.getItem("pd.auth.refreshToken"); - const token = localStorage.getItem("pd.auth.token"); - const gclb = localStorage.getItem("pd.auth.gclb"); - const overleafSession = localStorage.getItem("pd.auth.overleafSession"); - const projectId = localStorage.getItem("pd.projectId"); - const keys = Object.values(localStorageKey); - const values = keys.map((key) => localStorage.getItem(key)); - localStorage.clear(); - - localStorage.setItem("pd.auth.refreshToken", refreshToken || ""); - localStorage.setItem("pd.auth.token", token || ""); - localStorage.setItem("pd.auth.gclb", gclb || ""); - localStorage.setItem("pd.auth.overleafSession", overleafSession || ""); - localStorage.setItem("pd.projectId", projectId || ""); - - keys.forEach((key, index) => { - localStorage.setItem(key, values[index] || ""); + // Get all keys from storage + const allKeys = storage.keys(); + + // Identify keys to preserve (auth, devtool, projectId) + const keysToPreserve = allKeys.filter((key) => + PRESERVED_KEY_PREFIXES.some((prefix) => key.startsWith(prefix)) + ); + + // Save values of keys to preserve + const preservedValues: Record = {}; + keysToPreserve.forEach((key) => { + preservedValues[key] = storage.getItem(key); + }); + + // Also preserve devtool store keys + const devtoolKeys = Object.values(localStorageKey); + devtoolKeys.forEach((key) => { + if (!preservedValues[key]) { + preservedValues[key] = storage.getItem(key); + } + }); + + // Clear all storage + storage.clear(); + + // Restore preserved values + Object.entries(preservedValues).forEach(([key, value]) => { + if (value !== null) { + storage.setItem(key, value); + } }); window.location.reload(); diff --git a/webapp/_webapp/src/views/settings/sections/user-developer-tools.tsx b/webapp/_webapp/src/views/settings/sections/user-developer-tools.tsx index ff7e19c..175a007 100644 --- a/webapp/_webapp/src/views/settings/sections/user-developer-tools.tsx +++ b/webapp/_webapp/src/views/settings/sections/user-developer-tools.tsx @@ -4,10 +4,13 @@ import { useSettingStore } from "../../../stores/setting-store"; import { SettingItemInput } from "../setting-item-input"; import { useEffect, useState } from "react"; import apiclient, { apiclientV2, getEndpointFromLocalStorage, resetApiClientEndpoint } from "../../../libs/apiclient"; +import { useAdapter } from "../../../adapters/context"; export const UserDeveloperTools = () => { const { conversationMode, setConversationMode } = useSettingStore(); const [endpoint, setEndpoint] = useState(getEndpointFromLocalStorage()); + const adapter = useAdapter(); + const documentId = adapter.getDocumentId?.() || "N/A"; useEffect(() => { apiclient.updateBaseURL(endpoint, "v1"); @@ -45,6 +48,13 @@ export const UserDeveloperTools = () => { }} /> +
+
+

Document ID

+

{documentId}

+
+
+
* developer settings stored locally, will be reset when you clear your browser data
diff --git a/webapp/_webapp/vite.config.ts b/webapp/_webapp/vite.config.ts index ed3b393..5512013 100644 --- a/webapp/_webapp/vite.config.ts +++ b/webapp/_webapp/vite.config.ts @@ -82,6 +82,10 @@ const configs: Record = { draft.build.copyPublicDir = true; draft.plugins.push(generateManifestPlugin()); }), + office: generateConfig("./src/views/office/app.tsx", "office", (draft) => { + draft.build.emptyOutDir = true; + draft.build.outDir = "dist/office"; + }), background: generateConfig("./src/background.ts", "background"), intermediate: generateConfig("./src/intermediate.ts", "intermediate"), settings: generateConfig("./src/views/extension-settings/app.tsx", "settings"),