From 006f48fe1fca9347f39a752762e8d67c008748b9 Mon Sep 17 00:00:00 2001 From: MannuVilasara Date: Sat, 1 Nov 2025 10:30:33 +0530 Subject: [PATCH 1/3] migrate motia => bullmq --- backend/.env.example | 7 +- backend/package.json | 1 + backend/pnpm-lock.yaml | 260 +- backend/server.js | 90 +- backend/src/config/index.js | 18 + backend/src/config/queue.js | 160 + backend/src/config/schedulers.js | 112 + .../src/controllers/v2/motia.controller.js | 328 - backend/src/controllers/v2/page.controller.js | 28 +- backend/src/routes/index.js | 2 - backend/src/routes/v2/index.js | 4 +- backend/src/routes/v2/motia.routes.js | 67 - backend/src/utils/motia.utils.js | 48 - backend/src/workers/imageCleanup.worker.js | 119 + backend/src/workers/imageUpload.worker.js | 118 + backend/src/workers/pageSave.worker.js | 144 + backend/src/workers/taskReminder.worker.js | 146 + docker-compose.yml | 63 +- docs/backend.md | 41 +- docs/bullmq-jobs.md | 380 + motia/.cursor/architecture/architecture.mdc | 96 - motia/.cursor/architecture/error-handling.mdc | 122 - motia/.cursor/index.mdc | 34 - motia/.cursor/rules/motia/api-steps.mdc | 425 - motia/.cursor/rules/motia/cron-steps.mdc | 171 - motia/.cursor/rules/motia/event-steps.mdc | 218 - motia/.cursor/rules/motia/middlewares.mdc | 217 - .../rules/motia/realtime-streaming.mdc | 380 - .../.cursor/rules/motia/state-management.mdc | 136 - motia/.cursor/rules/motia/ui-steps.mdc | 76 - motia/.cursor/rules/motia/virtual-steps.mdc | 251 - motia/.dockerignore | 20 - motia/.env.example | 17 - motia/.gitignore | 8 - motia/Dockerfile | 28 - motia/README.md | 97 - motia/motia-workbench.json | 19 - motia/package.json | 26 - motia/pnpm-lock.yaml | 7819 ----------------- motia/steps/async-image-upload.step.ts | 62 - motia/steps/async-page-save.step.ts | 62 - motia/steps/cleanup-marked-images.step.ts | 78 - motia/steps/cleanup-orphaned-images.step.ts | 73 - motia/steps/health-check.step.ts | 29 - motia/steps/process-image-upload.step.ts | 88 - motia/steps/process-page-save.step.ts | 86 - motia/steps/scheduled-image-cleanup.step.ts | 44 - motia/steps/scheduled-task-reminders.step.ts | 34 - motia/steps/send-task-reminders.step.ts | 75 - motia/steps/trigger-image-cleanup.step.ts | 72 - motia/steps/trigger-task-reminders.step.ts | 58 - motia/tsconfig.json | 19 - motia/types.d.ts | 83 - package.json | 7 +- 54 files changed, 1601 insertions(+), 11565 deletions(-) create mode 100644 backend/src/config/queue.js create mode 100644 backend/src/config/schedulers.js delete mode 100644 backend/src/controllers/v2/motia.controller.js delete mode 100644 backend/src/routes/v2/motia.routes.js delete mode 100644 backend/src/utils/motia.utils.js create mode 100644 backend/src/workers/imageCleanup.worker.js create mode 100644 backend/src/workers/imageUpload.worker.js create mode 100644 backend/src/workers/pageSave.worker.js create mode 100644 backend/src/workers/taskReminder.worker.js create mode 100644 docs/bullmq-jobs.md delete mode 100644 motia/.cursor/architecture/architecture.mdc delete mode 100644 motia/.cursor/architecture/error-handling.mdc delete mode 100644 motia/.cursor/index.mdc delete mode 100644 motia/.cursor/rules/motia/api-steps.mdc delete mode 100644 motia/.cursor/rules/motia/cron-steps.mdc delete mode 100644 motia/.cursor/rules/motia/event-steps.mdc delete mode 100644 motia/.cursor/rules/motia/middlewares.mdc delete mode 100644 motia/.cursor/rules/motia/realtime-streaming.mdc delete mode 100644 motia/.cursor/rules/motia/state-management.mdc delete mode 100644 motia/.cursor/rules/motia/ui-steps.mdc delete mode 100644 motia/.cursor/rules/motia/virtual-steps.mdc delete mode 100644 motia/.dockerignore delete mode 100644 motia/.env.example delete mode 100644 motia/.gitignore delete mode 100644 motia/Dockerfile delete mode 100644 motia/README.md delete mode 100644 motia/motia-workbench.json delete mode 100644 motia/package.json delete mode 100644 motia/pnpm-lock.yaml delete mode 100644 motia/steps/async-image-upload.step.ts delete mode 100644 motia/steps/async-page-save.step.ts delete mode 100644 motia/steps/cleanup-marked-images.step.ts delete mode 100644 motia/steps/cleanup-orphaned-images.step.ts delete mode 100644 motia/steps/health-check.step.ts delete mode 100644 motia/steps/process-image-upload.step.ts delete mode 100644 motia/steps/process-page-save.step.ts delete mode 100644 motia/steps/scheduled-image-cleanup.step.ts delete mode 100644 motia/steps/scheduled-task-reminders.step.ts delete mode 100644 motia/steps/send-task-reminders.step.ts delete mode 100644 motia/steps/trigger-image-cleanup.step.ts delete mode 100644 motia/steps/trigger-task-reminders.step.ts delete mode 100644 motia/tsconfig.json delete mode 100644 motia/types.d.ts diff --git a/backend/.env.example b/backend/.env.example index 43b2465..a38cc65 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -15,10 +15,9 @@ CLOUDINARY_CLOUD_NAME=your_cloud_name CLOUDINARY_API_KEY=your_cloudinary_api_key CLOUDINARY_SECRET=your_clodinary_secret_key -# Motia Integration -USE_MOTIA=false -MOTIA_URL=http://localhost:3001 +# Redis Configuration +REDIS_URL=redis://localhost:6379 -# Cron Jobs (disable when using Motia) +# Cron Jobs DISABLE_REMINDER_CRON=true DISABLE_IMAGE_CLEANUP_CRON=true \ No newline at end of file diff --git a/backend/package.json b/backend/package.json index ab52511..c2e913c 100644 --- a/backend/package.json +++ b/backend/package.json @@ -18,6 +18,7 @@ "dependencies": { "axios": "^1.12.2", "bcryptjs": "^3.0.2", + "bullmq": "^5.63.0", "cloudinary": "^2.8.0", "cookie-parser": "^1.4.7", "cors": "^2.8.5", diff --git a/backend/pnpm-lock.yaml b/backend/pnpm-lock.yaml index 6a084f1..2634de4 100644 --- a/backend/pnpm-lock.yaml +++ b/backend/pnpm-lock.yaml @@ -13,6 +13,9 @@ importers: bcryptjs: specifier: ^3.0.2 version: 3.0.2 + bullmq: + specifier: ^5.63.0 + version: 5.63.0 cloudinary: specifier: ^2.8.0 version: 2.8.0 @@ -1131,6 +1134,12 @@ packages: } engines: { node: '>=18.18' } + '@ioredis/commands@1.4.0': + resolution: + { + integrity: sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ==, + } + '@isaacs/cliui@8.0.2': resolution: { @@ -1325,6 +1334,54 @@ packages: integrity: sha512-6nZrq5kfAz0POWyhljnbWQQJQ5uT8oE2ddX303q1uY0tWsivWKgBDXBBvuFPwOqRRalXJuVO9EjOdVtuhLX0zg==, } + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': + resolution: + { + integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==, + } + cpu: [arm64] + os: [darwin] + + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3': + resolution: + { + integrity: sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==, + } + cpu: [x64] + os: [darwin] + + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3': + resolution: + { + integrity: sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==, + } + cpu: [arm64] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3': + resolution: + { + integrity: sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==, + } + cpu: [arm] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3': + resolution: + { + integrity: sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==, + } + cpu: [x64] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': + resolution: + { + integrity: sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==, + } + cpu: [x64] + os: [win32] + '@napi-rs/wasm-runtime@0.2.12': resolution: { @@ -2111,6 +2168,12 @@ packages: integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==, } + bullmq@5.63.0: + resolution: + { + integrity: sha512-HT1iM3Jt4bZeg3Ru/MxrOy2iIItxcl1Pz5Ync1Vrot70jBpVguMxFEiSaDU57BwYwR4iwnObDnzct2lirKkX5A==, + } + bytes@3.1.2: resolution: { @@ -2367,6 +2430,13 @@ packages: } engines: { node: '>= 0.10' } + cron-parser@4.9.0: + resolution: + { + integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==, + } + engines: { node: '>=12.0.0' } + cross-spawn@7.0.6: resolution: { @@ -2463,6 +2533,13 @@ packages: } engines: { node: '>=0.4.0' } + denque@2.1.0: + resolution: + { + integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==, + } + engines: { node: '>=0.10' } + depd@2.0.0: resolution: { @@ -2470,6 +2547,13 @@ packages: } engines: { node: '>= 0.8' } + detect-libc@2.1.2: + resolution: + { + integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==, + } + engines: { node: '>=8' } + detect-newline@3.1.0: resolution: { @@ -3269,6 +3353,13 @@ packages: } engines: { node: '>= 0.4' } + ioredis@5.8.2: + resolution: + { + integrity: sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q==, + } + engines: { node: '>=12.22.0' } + ip-address@10.0.1: resolution: { @@ -3906,12 +3997,24 @@ packages: integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==, } + lodash.defaults@4.2.0: + resolution: + { + integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==, + } + lodash.includes@4.3.0: resolution: { integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==, } + lodash.isarguments@3.1.0: + resolution: + { + integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==, + } + lodash.isboolean@3.0.3: resolution: { @@ -3979,6 +4082,13 @@ packages: integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, } + luxon@3.7.2: + resolution: + { + integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==, + } + engines: { node: '>=12' } + make-dir@4.0.0: resolution: { @@ -4171,6 +4281,19 @@ packages: integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, } + msgpackr-extract@3.0.3: + resolution: + { + integrity: sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==, + } + hasBin: true + + msgpackr@1.11.5: + resolution: + { + integrity: sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA==, + } + napi-postinstall@0.3.4: resolution: { @@ -4192,6 +4315,12 @@ packages: } engines: { node: '>= 0.6' } + node-abort-controller@3.1.1: + resolution: + { + integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==, + } + node-cron@4.2.1: resolution: { @@ -4199,6 +4328,13 @@ packages: } engines: { node: '>=6.0.0' } + node-gyp-build-optional-packages@5.2.2: + resolution: + { + integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==, + } + hasBin: true + node-int64@0.4.0: resolution: { @@ -4628,6 +4764,20 @@ packages: } engines: { node: '>=8.10.0' } + redis-errors@1.2.0: + resolution: + { + integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==, + } + engines: { node: '>=4' } + + redis-parser@3.0.0: + resolution: + { + integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==, + } + engines: { node: '>=4' } + redis@5.8.3: resolution: { @@ -4960,6 +5110,12 @@ packages: } engines: { node: '>=10' } + standard-as-callback@2.1.0: + resolution: + { + integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==, + } + statuses@2.0.1: resolution: { @@ -5343,6 +5499,13 @@ packages: } engines: { node: '>= 0.4.0' } + uuid@11.1.0: + resolution: + { + integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==, + } + hasBin: true + uuid@13.0.0: resolution: { @@ -6332,6 +6495,8 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} + '@ioredis/commands@1.4.0': {} + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -6553,6 +6718,24 @@ snapshots: dependencies: sparse-bitfield: 3.0.3 + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': + optional: true + '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.6.0 @@ -7030,6 +7213,18 @@ snapshots: buffer-from@1.1.2: {} + bullmq@5.63.0: + dependencies: + cron-parser: 4.9.0 + ioredis: 5.8.2 + msgpackr: 1.11.5 + node-abort-controller: 3.1.1 + semver: 7.7.3 + tslib: 2.8.1 + uuid: 11.1.0 + transitivePeerDependencies: + - supports-color + bytes@3.1.2: {} call-bind-apply-helpers@1.0.2: @@ -7158,6 +7353,10 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 + cron-parser@4.9.0: + dependencies: + luxon: 3.7.2 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -7212,8 +7411,13 @@ snapshots: delayed-stream@1.0.0: {} + denque@2.1.0: {} + depd@2.0.0: {} + detect-libc@2.1.2: + optional: true + detect-newline@3.1.0: {} dezalgo@1.0.4: @@ -7792,6 +7996,20 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 + ioredis@5.8.2: + dependencies: + '@ioredis/commands': 1.4.0 + cluster-key-slot: 1.1.2 + debug: 4.4.3(supports-color@5.5.0) + denque: 2.1.0 + lodash.defaults: 4.2.0 + lodash.isarguments: 3.1.0 + redis-errors: 1.2.0 + redis-parser: 3.0.0 + standard-as-callback: 2.1.0 + transitivePeerDependencies: + - supports-color + ip-address@10.0.1: {} ipaddr.js@1.9.1: {} @@ -8350,8 +8568,12 @@ snapshots: lodash.debounce@4.0.8: {} + lodash.defaults@4.2.0: {} + lodash.includes@4.3.0: {} + lodash.isarguments@3.1.0: {} + lodash.isboolean@3.0.3: {} lodash.isinteger@4.0.4: {} @@ -8383,6 +8605,8 @@ snapshots: dependencies: yallist: 3.1.1 + luxon@3.7.2: {} + make-dir@4.0.0: dependencies: semver: 7.7.3 @@ -8476,14 +8700,37 @@ snapshots: ms@2.1.3: {} + msgpackr-extract@3.0.3: + dependencies: + node-gyp-build-optional-packages: 5.2.2 + optionalDependencies: + '@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.3 + optional: true + + msgpackr@1.11.5: + optionalDependencies: + msgpackr-extract: 3.0.3 + napi-postinstall@0.3.4: {} natural-compare@1.4.0: {} negotiator@1.0.0: {} + node-abort-controller@3.1.1: {} + node-cron@4.2.1: {} + node-gyp-build-optional-packages@5.2.2: + dependencies: + detect-libc: 2.1.2 + optional: true + node-int64@0.4.0: {} node-releases@2.0.26: {} @@ -8721,6 +8968,12 @@ snapshots: dependencies: picomatch: 2.3.1 + redis-errors@1.2.0: {} + + redis-parser@3.0.0: + dependencies: + redis-errors: 1.2.0 + redis@5.8.3: dependencies: '@redis/bloom': 5.8.3(@redis/client@5.8.3) @@ -8950,6 +9203,8 @@ snapshots: dependencies: escape-string-regexp: 2.0.0 + standard-as-callback@2.1.0: {} + statuses@2.0.1: {} statuses@2.0.2: {} @@ -9089,8 +9344,7 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 - tslib@2.8.1: - optional: true + tslib@2.8.1: {} type-check@0.4.0: dependencies: @@ -9205,6 +9459,8 @@ snapshots: utils-merge@1.0.1: {} + uuid@11.1.0: {} + uuid@13.0.0: {} v8-to-istanbul@9.3.0: diff --git a/backend/server.js b/backend/server.js index 6ba99f0..8a83f96 100644 --- a/backend/server.js +++ b/backend/server.js @@ -8,8 +8,12 @@ import { connectDatabase, getDatabaseStatus } from './src/config/database.js'; import config from './src/config/index.js'; import logger from './src/utils/logger.js'; import { ConnectRedis } from './src/config/redis.js'; -import { startReminderCronJob, stopReminderCronJob } from './src/jobs/reminderJob.js'; -import { startImageCleanupCronJob, stopImageCleanupCronJob } from './src/jobs/imageCleanupJob.js'; +import { initializeQueues, closeQueues } from './src/config/queue.js'; +import { initializeScheduledJobs } from './src/config/schedulers.js'; +import createPageSaveWorker from './src/workers/pageSave.worker.js'; +import createImageUploadWorker from './src/workers/imageUpload.worker.js'; +import createImageCleanupWorker from './src/workers/imageCleanup.worker.js'; +import createTaskReminderWorker from './src/workers/taskReminder.worker.js'; // Handle uncaught exceptions process.on('uncaughtException', (err) => { @@ -34,44 +38,72 @@ const startServer = async () => { const dbStatus = getDatabaseStatus(); logger.info(`📊 Database Status: ${dbStatus.status}`); + // Initialize BullMQ (optional - will warn if Redis unavailable) + let workers = null; + try { + await initializeQueues(); + + // Start BullMQ workers + workers = { + pageSave: createPageSaveWorker(), + imageUpload: createImageUploadWorker(), + imageCleanup: createImageCleanupWorker(), + taskReminder: createTaskReminderWorker(), + }; + logger.info('✅ All BullMQ workers started'); + + // Initialize scheduled jobs (if enabled) + if (config.cron.reminderJobEnabled && config.cron.imageCleanupJobEnabled) { + await initializeScheduledJobs(); + } else { + if (!config.cron.reminderJobEnabled) { + logger.info('⏰ Task reminder scheduled job disabled via configuration'); + } + if (!config.cron.imageCleanupJobEnabled) { + logger.info('🖼️ Image cleanup scheduled job disabled via configuration'); + } + } + } catch (bullmqError) { + logger.warn( + '⚠️ BullMQ initialization failed - background jobs will not work:', + bullmqError.message + ); + logger.warn('⚠️ Please ensure Redis is running for background job processing'); + } + // Start Express server const server = app.listen(config.server.port, () => { logger.info('🚀 ZettaNote API Server Started'); - logger.info(`📍 Environment: ${config.server.nodeEnv}`); + logger.info(`� Environment: ${config.server.nodeEnv}`); logger.info(`🌐 Server running on port ${config.server.port}`); - logger.info(`🔗 API available at: http://localhost:${config.server.port}/api`); + logger.info(`� API available at: http://localhost:${config.server.port}/api`); logger.info(`💚 Health check: http://localhost:${config.server.port}/api/health`); }); - // Start reminder cron job (if enabled) - let reminderTask = null; - if (config.cron.reminderJobEnabled) { - reminderTask = startReminderCronJob(); - logger.info('⏰ Reminder cron job started'); - } else { - logger.info('⏰ Reminder cron job disabled via configuration'); - } - - // Start image cleanup cron job (if enabled) - let imageCleanupTasks = null; - if (config.cron.imageCleanupJobEnabled) { - imageCleanupTasks = startImageCleanupCronJob(); - logger.info('🖼️ Image cleanup cron job started'); - } else { - logger.info('🖼️ Image cleanup cron job disabled via configuration'); - } - // Graceful shutdown const shutdown = async (signal) => { logger.info(`\n${signal} received. Starting graceful shutdown...`); - if (reminderTask) { - stopReminderCronJob(reminderTask); - logger.info('⏰ Reminder cron job stopped'); - } - if (imageCleanupTasks) { - stopImageCleanupCronJob(imageCleanupTasks); - logger.info('🖼️ Image cleanup cron job stopped'); + // Close BullMQ workers if they were started + if (workers) { + try { + await Promise.all([ + workers.pageSave.close(), + workers.imageUpload.close(), + workers.imageCleanup.close(), + workers.taskReminder.close(), + ]); + logger.info('✅ All BullMQ workers closed'); + } catch (err) { + logger.error('❌ Error closing workers:', err); + } + + // Close BullMQ queues + try { + await closeQueues(); + } catch (err) { + logger.error('❌ Error closing queues:', err); + } } server.close(async () => { diff --git a/backend/src/config/index.js b/backend/src/config/index.js index 37aecae..63f8b95 100644 --- a/backend/src/config/index.js +++ b/backend/src/config/index.js @@ -14,6 +14,24 @@ const config = { // Redis Configuration redis: { url: process.env.REDIS_URL || 'redis://localhost:6379', + host: (() => { + const url = process.env.REDIS_URL || 'redis://localhost:6379'; + try { + const parsed = new URL(url); + return parsed.hostname; + } catch { + return 'localhost'; + } + })(), + port: (() => { + const url = process.env.REDIS_URL || 'redis://localhost:6379'; + try { + const parsed = new URL(url); + return parseInt(parsed.port || '6379', 10); + } catch { + return 6379; + } + })(), }, // Database Configuration diff --git a/backend/src/config/queue.js b/backend/src/config/queue.js new file mode 100644 index 0000000..16985a8 --- /dev/null +++ b/backend/src/config/queue.js @@ -0,0 +1,160 @@ +/** + * BullMQ Queue Configuration + * @description Configures and exports BullMQ queues for background job processing + */ + +import { Queue } from 'bullmq'; +import config from './index.js'; +import logger from '../utils/logger.js'; + +/** + * Check if Redis configuration is available + * @returns {boolean} True if Redis is explicitly configured (not just defaults) + */ +const isRedisConfigured = () => { + // Only return true if REDIS_URL is explicitly set in environment + // Don't use defaults to avoid connection attempts to unconfigured Redis + return !!process.env.REDIS_URL; +}; + +/** + * Get Redis connection configuration for BullMQ + * @returns {object|null} Redis connection config or null if not configured + */ +const getRedisConnection = () => { + if (!isRedisConfigured()) { + return null; + } + + return { + host: config.redis.host, + port: config.redis.port, + maxRetriesPerRequest: null, // BullMQ recommendation + enableOfflineQueue: false, // Don't queue commands if Redis is down + }; +}; + +/** + * Get default queue options + * @returns {object|null} Queue options or null if Redis not configured + */ +const getDefaultQueueOptions = () => { + const redisConnection = getRedisConnection(); + if (!redisConnection) { + return null; + } + + return { + connection: redisConnection, + defaultJobOptions: { + attempts: 3, + backoff: { + type: 'exponential', + delay: 5000, // Start with 5 seconds + }, + removeOnComplete: { + age: 86400, // Keep completed jobs for 24 hours + count: 1000, // Keep last 1000 jobs + }, + removeOnFail: { + age: 604800, // Keep failed jobs for 7 days + count: 5000, + }, + }, + }; +}; + +/** + * Queues - will be initialized when initializeQueues() is called + */ +export let pageSaveQueue = null; +export let imageUploadQueue = null; +export let imageCleanupQueue = null; +export let taskReminderQueue = null; + +/** + * Initialize all queues and log their status + */ +export const initializeQueues = async () => { + // Check if Redis is configured + if (!isRedisConfigured()) { + logger.warn('⚠️ Redis not configured - BullMQ queues will not be available'); + logger.warn('⚠️ Background jobs will run synchronously'); + throw new Error('Redis not configured'); + } + + try { + logger.info('🚀 Initializing BullMQ queues...'); + + // Get queue options + const queueOptions = getDefaultQueueOptions(); + if (!queueOptions) { + throw new Error('Failed to get queue options'); + } + + // Create queues only when Redis is available + pageSaveQueue = new Queue('page-save', queueOptions); + imageUploadQueue = new Queue('image-upload', queueOptions); + imageCleanupQueue = new Queue('image-cleanup', queueOptions); + taskReminderQueue = new Queue('task-reminder', queueOptions); + + // Test connection by trying to add a test job and removing it + const testJob = await pageSaveQueue.add( + 'test-connection', + {}, + { + removeOnComplete: true, + removeOnFail: true, + } + ); + await testJob.remove(); + + logger.info('✅ Redis connection successful for BullMQ'); + logger.info('✅ All BullMQ queues initialized successfully'); + logger.info(' - page-save queue ready'); + logger.info(' - image-upload queue ready'); + logger.info(' - image-cleanup queue ready'); + logger.info(' - task-reminder queue ready'); + } catch (error) { + logger.error('❌ Failed to initialize BullMQ queues:', error.message); + logger.warn('⚠️ Background jobs will run synchronously'); + // Reset queues to null on error + pageSaveQueue = null; + imageUploadQueue = null; + imageCleanupQueue = null; + taskReminderQueue = null; + throw error; + } +}; + +/** + * Close all queue connections + */ +export const closeQueues = async () => { + // Only close if queues were initialized + if (!pageSaveQueue) { + return; + } + + try { + await Promise.all([ + pageSaveQueue.close(), + imageUploadQueue.close(), + imageCleanupQueue.close(), + taskReminderQueue.close(), + ]); + logger.info('✅ All BullMQ queues closed'); + } catch (error) { + logger.error('❌ Error closing BullMQ queues:', error); + throw error; + } +}; + +export default { + pageSaveQueue, + imageUploadQueue, + imageCleanupQueue, + taskReminderQueue, + initializeQueues, + closeQueues, +}; diff --git a/backend/src/config/schedulers.js b/backend/src/config/schedulers.js new file mode 100644 index 0000000..f6f6e1e --- /dev/null +++ b/backend/src/config/schedulers.js @@ -0,0 +1,112 @@ +/** + * BullMQ Schedulers + * @description Sets up repeatable jobs for scheduled background tasks + */ + +import { imageCleanupQueue, taskReminderQueue } from '../config/queue.js'; +import logger from '../utils/logger.js'; + +/** + * Initialize scheduled jobs + * @description Sets up repeatable jobs for image cleanup and task reminders + */ +export const initializeScheduledJobs = async () => { + // Check if queues are available + if (!imageCleanupQueue || !taskReminderQueue) { + logger.warn('⚠️ BullMQ queues not available - skipping scheduled jobs initialization'); + return; + } + + try { + logger.info('🕐 Initializing scheduled jobs...'); + + // Image cleanup job - runs every 6 hours + await imageCleanupQueue.add( + 'scheduled-comprehensive-cleanup', + { + cleanupType: 'comprehensive', + batchSize: 50, + }, + { + repeat: { + pattern: '0 */6 * * *', // Every 6 hours at minute 0 + }, + jobId: 'scheduled-image-cleanup', // Unique job ID to prevent duplicates + } + ); + logger.info('✅ Scheduled image cleanup job (every 6 hours)'); + + // Task reminder job - runs every 5 minutes + await taskReminderQueue.add( + 'scheduled-reminder-check', + { + checkType: 'all', + }, + { + repeat: { + pattern: '*/5 * * * *', // Every 5 minutes + }, + jobId: 'scheduled-task-reminders', // Unique job ID to prevent duplicates + } + ); + logger.info('✅ Scheduled task reminder job (every 5 minutes)'); + + // Run initial cleanup on startup + await imageCleanupQueue.add('startup-cleanup', { + cleanupType: 'comprehensive', + batchSize: 50, + }); + logger.info('✅ Triggered initial image cleanup'); + + // Run initial reminder check on startup + await taskReminderQueue.add('startup-reminder-check', { + checkType: 'all', + }); + logger.info('✅ Triggered initial reminder check'); + + logger.info('✅ All scheduled jobs initialized successfully'); + } catch (error) { + logger.error('❌ Failed to initialize scheduled jobs:', error); + throw error; + } +}; + +/** + * Remove scheduled jobs + * @description Removes all repeatable jobs (useful for cleanup) + */ +export const removeScheduledJobs = async () => { + // Check if queues are available + if (!imageCleanupQueue || !taskReminderQueue) { + logger.warn('⚠️ BullMQ queues not available - skipping scheduled jobs removal'); + return; + } + + try { + logger.info('Removing scheduled jobs...'); + + // Get and remove repeatable jobs from image cleanup queue + const imageCleanupRepeatableJobs = await imageCleanupQueue.getRepeatableJobs(); + for (const job of imageCleanupRepeatableJobs) { + await imageCleanupQueue.removeRepeatableByKey(job.key); + logger.info(`Removed repeatable job: ${job.name} from image-cleanup queue`); + } + + // Get and remove repeatable jobs from task reminder queue + const taskReminderRepeatableJobs = await taskReminderQueue.getRepeatableJobs(); + for (const job of taskReminderRepeatableJobs) { + await taskReminderQueue.removeRepeatableByKey(job.key); + logger.info(`Removed repeatable job: ${job.name} from task-reminder queue`); + } + + logger.info('✅ All scheduled jobs removed'); + } catch (error) { + logger.error('❌ Error removing scheduled jobs:', error); + throw error; + } +}; + +export default { + initializeScheduledJobs, + removeScheduledJobs, +}; diff --git a/backend/src/controllers/v2/motia.controller.js b/backend/src/controllers/v2/motia.controller.js deleted file mode 100644 index efbd950..0000000 --- a/backend/src/controllers/v2/motia.controller.js +++ /dev/null @@ -1,328 +0,0 @@ -import { z } from 'zod'; -import { STATUS_CODES } from '../../constants/statusCodes.js'; -import logger from '../../utils/logger.js'; -import { cleanupMarkedImages, markOrphanedImages } from '../../utils/image.utils.js'; -import { sendTaskReminderEmail, sendTaskOverdueEmail } from '../v1/mailer.controller.js'; -import TaskModel from '../../models/Task.model.js'; -import Page from '../../models/Page.model.js'; -import { updateImageReferences, getContentImageIds } from '../../utils/image.utils.js'; -import { safeRedisCall } from '../../config/redis.js'; -import cloudinary from '../../config/cloudinary.js'; -import Image from '../../models/Image.model.js'; - -/** - * Cleanup Marked Images Endpoint (called by Motia) - * @param {object} req - Express request object - * @returns {object} Response with cleanup results - */ -export const cleanupMarkedImagesEndpoint = async (req) => { - try { - const schema = z.object({ - batchSize: z.number().min(1).max(100).default(50), - jobId: z.string(), - }); - - const { batchSize, jobId } = schema.parse(req.body); - - logger.info('Processing marked images cleanup', { jobId, batchSize }); - - const result = await cleanupMarkedImages(batchSize); - - return { - resStatus: STATUS_CODES.OK, - resMessage: { - success: true, - deletedCount: result.deletedCount, - failedCount: result.failedCount, - totalProcessed: result.totalProcessed, - }, - }; - } catch (error) { - logger.error('Marked images cleanup failed', { error: error.message }); - return { - resStatus: STATUS_CODES.INTERNAL_SERVER_ERROR, - resMessage: { - success: false, - error: error.message, - }, - }; - } -}; - -/** - * Mark Orphaned Images Endpoint (called by Motia) - * @param {object} req - Express request object - * @returns {object} Response with marking results - */ -export const markOrphanedImagesEndpoint = async (req) => { - try { - const schema = z.object({ - jobId: z.string(), - }); - - const { jobId } = schema.parse(req.body); - - logger.info('Processing orphaned images detection', { jobId }); - - const markedCount = await markOrphanedImages(); - - return { - resStatus: STATUS_CODES.OK, - resMessage: { - success: true, - markedCount, - }, - }; - } catch (error) { - logger.error('Orphaned images detection failed', { error: error.message }); - return { - resStatus: STATUS_CODES.INTERNAL_SERVER_ERROR, - resMessage: { - success: false, - error: error.message, - }, - }; - } -}; - -/** - * Check Task Reminders Endpoint (called by Motia) - * @param {object} req - Express request object - * @returns {object} Response with reminder results - */ -export const checkTaskRemindersEndpoint = async (req) => { - try { - const schema = z.object({ - jobId: z.string(), - checkType: z.enum(['all', 'one-hour', 'overdue']).default('all'), - }); - - const { jobId, checkType } = schema.parse(req.body); - - logger.info('Processing task reminders', { jobId, checkType }); - - const now = new Date(); - const oneHourFromNow = new Date(now.getTime() + 60 * 60 * 1000); - const oneHourWindow = 5 * 60 * 1000; - - let oneHourReminders = 0; - let overdueReminders = 0; - - // Check 1-hour reminders - if (checkType === 'all' || checkType === 'one-hour') { - const tasksNearing1Hour = await TaskModel.find({ - taskDeadline: { - $gte: new Date(oneHourFromNow.getTime() - oneHourWindow), - $lte: new Date(oneHourFromNow.getTime() + oneHourWindow), - }, - isTaskCompleted: false, - oneHourReminderSent: false, - }).populate('owner'); - - for (const task of tasksNearing1Hour) { - const emailResult = await sendTaskReminderEmail(task, '1 hour'); - if (emailResult.success) { - await TaskModel.findByIdAndUpdate(task._id, { oneHourReminderSent: true }); - oneHourReminders++; - } - } - } - - // Check overdue reminders - if (checkType === 'all' || checkType === 'overdue') { - const overdueTasks = await TaskModel.find({ - taskDeadline: { $lt: now }, - isTaskCompleted: false, - overdueReminderSent: false, - }).populate('owner'); - - for (const task of overdueTasks) { - const emailResult = await sendTaskOverdueEmail(task); - if (emailResult.success) { - await TaskModel.findByIdAndUpdate(task._id, { overdueReminderSent: true }); - overdueReminders++; - } - } - } - - return { - resStatus: STATUS_CODES.OK, - resMessage: { - success: true, - oneHourReminders, - overdueReminders, - }, - }; - } catch (error) { - logger.error('Task reminders check failed', { error: error.message }); - return { - resStatus: STATUS_CODES.INTERNAL_SERVER_ERROR, - resMessage: { - success: false, - error: error.message, - }, - }; - } -}; - -/** - * Async Page Save Endpoint (called by Motia) - * @param {object} req - Express request object - * @returns {object} Response with save results - */ -export const asyncPageSaveEndpoint = async (req) => { - try { - const schema = z.object({ - jobId: z.string(), - pageId: z.string(), - newPageData: z.string(), - userId: z.string(), - }); - - const { jobId, pageId, newPageData, userId } = schema.parse(req.body); - - logger.info('Processing async page save', { jobId, pageId, userId }); - - // Find page - const page = await Page.findById(pageId); - if (!page) { - return { - resStatus: STATUS_CODES.NOT_FOUND, - resMessage: { success: false, error: 'Page not found' }, - }; - } - - // Get current image IDs from the page content before updating - const previousImageIds = getContentImageIds(page.pageData); - - // Update page - page.pageData = newPageData; - await page.save(); - - // Handle image reference updates - const currentImageIds = getContentImageIds(newPageData); - const addedImages = currentImageIds.filter((id) => !previousImageIds.includes(id)); - const removedImages = previousImageIds.filter((id) => !currentImageIds.includes(id)); - - if (addedImages.length > 0 || removedImages.length > 0) { - try { - await updateImageReferences(pageId, addedImages, removedImages); - logger.info( - `Updated image references for page ${pageId}: +${addedImages.length} -${removedImages.length}` - ); - } catch (imageError) { - logger.error('Error updating image references:', imageError); - } - } - - const pageKey = `page:${pageId}`; - // Update cache in Redis - const saved = await safeRedisCall('set', pageKey, JSON.stringify(page), { - EX: 3600, // Cache for 1 hour - }); - if (saved) { - logger.info('Page cache updated in Redis'); - } - - // Invalidate related user caches (owner and shared users) - const ownerCacheKey = `user:${page.owner}:ownedPages`; - const sharedUserCacheKeys = (page.sharedTo || []).map((userId) => `user:${userId}:sharedPages`); - - // Invalidate owner cache - await safeRedisCall('del', ownerCacheKey); - - // Invalidate shared user caches in parallel - if (sharedUserCacheKeys.length > 0) { - await Promise.all(sharedUserCacheKeys.map((key) => safeRedisCall('del', key))); - } - - return { - resStatus: STATUS_CODES.OK, - resMessage: { - success: true, - message: 'Page saved successfully', - updated: true, - }, - }; - } catch (error) { - logger.error('Async page save failed', { error: error.message }); - return { - resStatus: STATUS_CODES.INTERNAL_SERVER_ERROR, - resMessage: { - success: false, - error: error.message, - }, - }; - } -}; - -/** - * Async Image Upload Endpoint (called by Motia) - * @param {object} req - Express request object - * @returns {object} Response with upload results - */ -export const asyncImageUploadEndpoint = async (req) => { - try { - const schema = z.object({ - jobId: z.string(), - image: z.string(), - originalName: z.string().optional(), - pageId: z.string().optional(), - userId: z.string(), - }); - - const { jobId, image, originalName, pageId, userId } = schema.parse(req.body); - - logger.info('Processing async image upload', { jobId, userId, pageId: pageId || 'none' }); - - // Upload image to Cloudinary - const timestamp = new Date().getTime(); - const uniqueId = `${userId}_${timestamp}`; - const cloudinaryRes = await cloudinary.uploader.upload(image, { - folder: 'notes', - public_id: `note_img_${uniqueId}`, - }); - - // Save image metadata to database - const imageDoc = new Image({ - publicId: cloudinaryRes.public_id, - url: cloudinaryRes.secure_url, - originalName: originalName || null, - size: cloudinaryRes.bytes || 0, - mimeType: cloudinaryRes.format ? `image/${cloudinaryRes.format}` : 'image/jpeg', - uploadedBy: userId, - usedInPages: pageId ? [pageId] : [], - referenceCount: pageId ? 1 : 0, - }); - - await imageDoc.save(); - - return { - resStatus: STATUS_CODES.OK, - resMessage: { - success: true, - message: 'Image uploaded successfully', - imageUrl: cloudinaryRes.secure_url, - imageId: cloudinaryRes.public_id, - dbImageId: imageDoc._id.toString(), - }, - }; - } catch (error) { - logger.error('Async image upload failed', { error: error.message }); - return { - resStatus: STATUS_CODES.INTERNAL_SERVER_ERROR, - resMessage: { - success: false, - error: error.message, - }, - }; - } -}; - -export default { - cleanupMarkedImagesEndpoint, - markOrphanedImagesEndpoint, - checkTaskRemindersEndpoint, - asyncPageSaveEndpoint, - asyncImageUploadEndpoint, -}; diff --git a/backend/src/controllers/v2/page.controller.js b/backend/src/controllers/v2/page.controller.js index dfbc0eb..f663a20 100644 --- a/backend/src/controllers/v2/page.controller.js +++ b/backend/src/controllers/v2/page.controller.js @@ -6,7 +6,7 @@ import { z } from 'zod'; import logger from '../../utils/logger.js'; import { safeRedisCall } from '../../config/redis.js'; import { updateImageReferences, getContentImageIds } from '../../utils/image.utils.js'; -import { MOTIA_CONFIG, triggerAsyncPageSave } from '../../utils/motia.utils.js'; +import { pageSaveQueue } from '../../config/queue.js'; /** * Helper function to get page name and ID @@ -80,27 +80,33 @@ export const savePage = async (req) => { }; } - // Use Motia for async processing if enabled - if (MOTIA_CONFIG.enabled) { - logger.info('Using Motia for async page save', { pageId, userId: user._id }); + // Use BullMQ for async processing if available + if (pageSaveQueue) { + try { + logger.info('Queueing page save job', { pageId, userId: user._id }); - const motiaResult = await triggerAsyncPageSave(pageId, newPageData, user._id.toString()); + const job = await pageSaveQueue.add('page-save', { + pageId, + newPageData, + userId: user._id.toString(), + }); - if (motiaResult.success) { return { resStatus: STATUS_CODES.ACCEPTED, // 202 - Accepted for processing resMessage: { message: 'Page save queued for processing', - jobId: motiaResult.jobId, + jobId: job.id, }, }; - } else { - logger.warn('Motia async save failed, falling back to sync', { + } catch (queueError) { + logger.warn('Failed to queue page save, falling back to sync', { pageId, - error: motiaResult.error, + error: queueError.message, }); - // Fall back to synchronous processing if Motia fails + // Fall back to synchronous processing if queue fails } + } else { + logger.debug('BullMQ not available, processing page save synchronously'); } // Synchronous save logic diff --git a/backend/src/routes/index.js b/backend/src/routes/index.js index 0735b17..39b32cd 100644 --- a/backend/src/routes/index.js +++ b/backend/src/routes/index.js @@ -36,7 +36,6 @@ import mailerRoutes from './v1/mailer.routes.js'; import oauthRoutes from './v1/oauth.routes.js'; import taskRoutes from './v1/task.routes.js'; import userRoutes from './v1/user.routes.js'; -import motiaRoutes from './v2/motia.routes.js'; router.use('/auth', authRoutes); router.use('/auth', oauthRoutes); @@ -45,6 +44,5 @@ router.use('/admin', adminRoutes); router.use('/mailer', mailerRoutes); router.use('/task', taskRoutes); router.use('/user', userRoutes); -router.use('/motia', motiaRoutes); export default router; diff --git a/backend/src/routes/v2/index.js b/backend/src/routes/v2/index.js index 26c265c..dd36f8c 100644 --- a/backend/src/routes/v2/index.js +++ b/backend/src/routes/v2/index.js @@ -1,12 +1,12 @@ import express from 'express'; import pageRoutes from './page.routes.js'; -import motiaRoutes from './motia.routes.js'; +// import motiaRoutes from './motia.routes.js'; const router = express.Router(); // V2 API Routes router.use('/pages', pageRoutes); -router.use('/motia', motiaRoutes); +// router.use('/motia', motiaRoutes); // Health check for v2 API router.get('/health', (req, res) => { diff --git a/backend/src/routes/v2/motia.routes.js b/backend/src/routes/v2/motia.routes.js deleted file mode 100644 index f8e644f..0000000 --- a/backend/src/routes/v2/motia.routes.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Motia Routes - * Routes for Motia service integration - */ - -import express from 'express'; -import { - cleanupMarkedImagesEndpoint, - markOrphanedImagesEndpoint, - checkTaskRemindersEndpoint, - asyncPageSaveEndpoint, - asyncImageUploadEndpoint, -} from '../../controllers/v2/motia.controller.js'; - -const router = express.Router(); - -/** - * POST /api/cleanup/marked-images - * @description Cleanup marked images (called by Motia) - * @access Internal (Motia service) - */ -router.post('/cleanup/marked-images', async (req, res) => { - const result = await cleanupMarkedImagesEndpoint(req); - res.status(result.resStatus).json(result.resMessage); -}); - -/** - * POST /api/cleanup/orphaned-images - * @description Mark orphaned images for deletion (called by Motia) - * @access Internal (Motia service) - */ -router.post('/cleanup/orphaned-images', async (req, res) => { - const result = await markOrphanedImagesEndpoint(req); - res.status(result.resStatus).json(result.resMessage); -}); - -/** - * POST /api/reminders/check - * @description Check and send task reminders (called by Motia) - * @access Internal (Motia service) - */ -router.post('/reminders/check', async (req, res) => { - const result = await checkTaskRemindersEndpoint(req); - res.status(result.resStatus).json(result.resMessage); -}); - -/** - * POST /api/pages/save-async - * @description Async page save processing (called by Motia) - * @access Internal (Motia service) - */ -router.post('/pages/save-async', async (req, res) => { - const result = await asyncPageSaveEndpoint(req); - res.status(result.resStatus).json(result.resMessage); -}); - -/** - * POST /api/images/upload-async - * @description Async image upload processing (called by Motia) - * @access Internal (Motia service) - */ -router.post('/images/upload-async', async (req, res) => { - const result = await asyncImageUploadEndpoint(req); - res.status(result.resStatus).json(result.resMessage); -}); - -export default router; diff --git a/backend/src/utils/motia.utils.js b/backend/src/utils/motia.utils.js deleted file mode 100644 index 06dcb72..0000000 --- a/backend/src/utils/motia.utils.js +++ /dev/null @@ -1,48 +0,0 @@ -import axios from 'axios'; -import logger from './logger.js'; - -/** - * Configuration for Motia integration - */ -const MOTIA_CONFIG = { - enabled: process.env.USE_MOTIA === 'true', - baseUrl: process.env.MOTIA_URL || 'http://localhost:3001', - timeout: 5000, // 5 seconds for initial trigger -}; - -/** - * Trigger async page save via Motia - * @param {string} pageId - The page ID to save - * @param {string} newPageData - The new page content - * @param {string} userId - The user ID performing the save - * @returns {Promise<{success: boolean, jobId?: string, error?: string}>} Result of the trigger - */ -const triggerAsyncPageSave = async (pageId, newPageData, userId) => { - try { - const response = await axios.post( - `${MOTIA_CONFIG.baseUrl}/pages/save`, - { - pageId, - newPageData, - userId, - }, - { - headers: { 'Content-Type': 'application/json' }, - timeout: MOTIA_CONFIG.timeout, - } - ); - - return { - success: true, - jobId: response.data.body?.jobId, - }; - } catch (error) { - logger.error('Failed to trigger async page save:', error.message); - return { - success: false, - error: error.message, - }; - } -}; - -export { MOTIA_CONFIG, triggerAsyncPageSave }; diff --git a/backend/src/workers/imageCleanup.worker.js b/backend/src/workers/imageCleanup.worker.js new file mode 100644 index 0000000..20eb6d6 --- /dev/null +++ b/backend/src/workers/imageCleanup.worker.js @@ -0,0 +1,119 @@ +/** + * Image Cleanup Worker + * @description BullMQ worker for processing image cleanup operations + */ + +import { Worker } from 'bullmq'; +import config from '../config/index.js'; +import logger from '../utils/logger.js'; +import { cleanupMarkedImages, markOrphanedImages } from '../utils/image.utils.js'; + +/** + * Redis connection configuration + */ +const redisConnection = { + host: config.redis.host, + port: config.redis.port, + maxRetriesPerRequest: null, +}; + +/** + * Process image cleanup job + * @param {object} job - BullMQ job + * @returns {object} Cleanup result + */ +const processImageCleanup = async (job) => { + const { cleanupType, batchSize = 50 } = job.data; + + logger.info('Processing image cleanup', { + jobId: job.id, + cleanupType, + batchSize, + attemptsMade: job.attemptsMade, + }); + + try { + const result = { + success: true, + markedCount: 0, + deletedCount: 0, + failedCount: 0, + totalProcessed: 0, + }; + + if (cleanupType === 'mark-orphaned' || cleanupType === 'comprehensive') { + // Mark orphaned images for deletion + const markedCount = await markOrphanedImages(); + result.markedCount = markedCount; + logger.info(`Marked ${markedCount} orphaned images for deletion`, { jobId: job.id }); + } + + if (cleanupType === 'cleanup-marked' || cleanupType === 'comprehensive') { + // Clean up marked images + const cleanupResult = await cleanupMarkedImages(batchSize); + result.deletedCount = cleanupResult.deletedCount; + result.failedCount = cleanupResult.failedCount; + result.totalProcessed = cleanupResult.totalProcessed; + logger.info( + `Cleaned up ${cleanupResult.deletedCount} marked images (${cleanupResult.failedCount} failed)`, + { jobId: job.id } + ); + } + + logger.info('Image cleanup completed successfully', { + jobId: job.id, + cleanupType, + ...result, + }); + + return result; + } catch (error) { + logger.error('Image cleanup failed', { + jobId: job.id, + cleanupType, + error: error.message, + attemptsMade: job.attemptsMade, + }); + throw error; // Will trigger retry if attempts remain + } +}; + +/** + * Create and start the image cleanup worker + * @returns {Worker} BullMQ worker instance + */ +export const createImageCleanupWorker = () => { + const worker = new Worker('image-cleanup', processImageCleanup, { + connection: redisConnection, + concurrency: 1, // Process one cleanup job at a time to avoid conflicts + }); + + // Event handlers + worker.on('completed', (job, result) => { + logger.info('Image cleanup job completed', { + jobId: job.id, + cleanupType: job.data.cleanupType, + markedCount: result.markedCount, + deletedCount: result.deletedCount, + duration: job.processedOn ? Date.now() - job.processedOn : 'N/A', + }); + }); + + worker.on('failed', (job, err) => { + logger.error('Image cleanup job failed permanently', { + jobId: job?.id, + cleanupType: job?.data?.cleanupType, + error: err.message, + attemptsMade: job?.attemptsMade, + }); + }); + + worker.on('error', (err) => { + logger.error('Image cleanup worker error:', err); + }); + + logger.info('✅ Image cleanup worker started'); + return worker; +}; + +export default createImageCleanupWorker; diff --git a/backend/src/workers/imageUpload.worker.js b/backend/src/workers/imageUpload.worker.js new file mode 100644 index 0000000..1436cfb --- /dev/null +++ b/backend/src/workers/imageUpload.worker.js @@ -0,0 +1,118 @@ +/** + * Image Upload Worker + * @description BullMQ worker for processing image uploads asynchronously + */ + +import { Worker } from 'bullmq'; +import config from '../config/index.js'; +import logger from '../utils/logger.js'; +import cloudinary from '../config/cloudinary.js'; +import Image from '../models/Image.model.js'; + +/** + * Redis connection configuration + */ +const redisConnection = { + host: config.redis.host, + port: config.redis.port, + maxRetriesPerRequest: null, +}; + +/** + * Process image upload job + * @param {object} job - BullMQ job + * @returns {object} Upload result + */ +const processImageUpload = async (job) => { + const { image, originalName, pageId, userId } = job.data; + + logger.info('Processing image upload', { + jobId: job.id, + userId, + pageId: pageId || 'none', + attemptsMade: job.attemptsMade, + }); + + try { + // Upload image to Cloudinary + const timestamp = new Date().getTime(); + const uniqueId = `${userId}_${timestamp}`; + const cloudinaryRes = await cloudinary.uploader.upload(image, { + folder: 'notes', + public_id: `note_img_${uniqueId}`, + }); + + // Save image metadata to database + const imageDoc = new Image({ + publicId: cloudinaryRes.public_id, + url: cloudinaryRes.secure_url, + originalName: originalName || null, + size: cloudinaryRes.bytes || 0, + mimeType: cloudinaryRes.format ? `image/${cloudinaryRes.format}` : 'image/jpeg', + uploadedBy: userId, + usedInPages: pageId ? [pageId] : [], + referenceCount: pageId ? 1 : 0, + }); + + await imageDoc.save(); + + logger.info('Image upload completed successfully', { + jobId: job.id, + imageId: cloudinaryRes.public_id, + dbImageId: imageDoc._id.toString(), + }); + + return { + success: true, + imageUrl: cloudinaryRes.secure_url, + imageId: cloudinaryRes.public_id, + dbImageId: imageDoc._id.toString(), + }; + } catch (error) { + logger.error('Image upload failed', { + jobId: job.id, + userId, + error: error.message, + attemptsMade: job.attemptsMade, + }); + throw error; // Will trigger retry if attempts remain + } +}; + +/** + * Create and start the image upload worker + * @returns {Worker} BullMQ worker instance + */ +export const createImageUploadWorker = () => { + const worker = new Worker('image-upload', processImageUpload, { + connection: redisConnection, + concurrency: 3, // Process 3 image uploads concurrently + }); + + // Event handlers + worker.on('completed', (job, result) => { + logger.info('Image upload job completed', { + jobId: job.id, + imageId: result.imageId, + duration: job.processedOn ? Date.now() - job.processedOn : 'N/A', + }); + }); + + worker.on('failed', (job, err) => { + logger.error('Image upload job failed permanently', { + jobId: job?.id, + userId: job?.data?.userId, + error: err.message, + attemptsMade: job?.attemptsMade, + }); + }); + + worker.on('error', (err) => { + logger.error('Image upload worker error:', err); + }); + + logger.info('✅ Image upload worker started'); + return worker; +}; + +export default createImageUploadWorker; diff --git a/backend/src/workers/pageSave.worker.js b/backend/src/workers/pageSave.worker.js new file mode 100644 index 0000000..4c67baf --- /dev/null +++ b/backend/src/workers/pageSave.worker.js @@ -0,0 +1,144 @@ +/** + * Page Save Worker + * @description BullMQ worker for processing page save operations asynchronously + */ + +import { Worker } from 'bullmq'; +import config from '../config/index.js'; +import logger from '../utils/logger.js'; +import Page from '../models/Page.model.js'; +import { updateImageReferences, getContentImageIds } from '../utils/image.utils.js'; +import { safeRedisCall } from '../config/redis.js'; + +/** + * Redis connection configuration + */ +const redisConnection = { + host: config.redis.host, + port: config.redis.port, + maxRetriesPerRequest: null, +}; + +/** + * Process page save job + * @param {object} job - BullMQ job + * @returns {object} Processing result + */ +const processPageSave = async (job) => { + const { pageId, newPageData, userId } = job.data; + + logger.info('Processing page save', { + jobId: job.id, + pageId, + userId, + attemptsMade: job.attemptsMade, + }); + + try { + // Find page + const page = await Page.findById(pageId); + if (!page) { + throw new Error(`Page not found: ${pageId}`); + } + + // Get current image IDs from the page content before updating + const previousImageIds = getContentImageIds(page.pageData); + + // Update page + page.pageData = newPageData; + await page.save(); + + // Handle image reference updates + const currentImageIds = getContentImageIds(newPageData); + const addedImages = currentImageIds.filter((id) => !previousImageIds.includes(id)); + const removedImages = previousImageIds.filter((id) => !currentImageIds.includes(id)); + + if (addedImages.length > 0 || removedImages.length > 0) { + try { + await updateImageReferences(pageId, addedImages, removedImages); + logger.info( + `Updated image references for page ${pageId}: +${addedImages.length} -${removedImages.length}` + ); + } catch (imageError) { + logger.error('Error updating image references:', imageError); + // Don't fail the job if image cleanup fails + } + } + + // Update cache in Redis + const pageKey = `page:${pageId}`; + const saved = await safeRedisCall('set', pageKey, JSON.stringify(page), { + EX: 3600, // Cache for 1 hour + }); + if (saved) { + logger.info('Page cache updated in Redis'); + } + + // Invalidate related user caches (owner and shared users) + const ownerCacheKey = `user:${page.owner}:ownedPages`; + const sharedUserCacheKeys = (page.sharedTo || []).map((userId) => `user:${userId}:sharedPages`); + + // Invalidate owner cache + await safeRedisCall('del', ownerCacheKey); + + // Invalidate shared user caches in parallel + if (sharedUserCacheKeys.length > 0) { + await Promise.all(sharedUserCacheKeys.map((key) => safeRedisCall('del', key))); + } + + logger.info('Page save completed successfully', { jobId: job.id, pageId }); + + return { + success: true, + pageId, + addedImages: addedImages.length, + removedImages: removedImages.length, + }; + } catch (error) { + logger.error('Page save failed', { + jobId: job.id, + pageId, + error: error.message, + attemptsMade: job.attemptsMade, + }); + throw error; // Will trigger retry if attempts remain + } +}; + +/** + * Create and start the page save worker + * @returns {Worker} BullMQ worker instance + */ +export const createPageSaveWorker = () => { + const worker = new Worker('page-save', processPageSave, { + connection: redisConnection, + concurrency: 5, // Process 5 page saves concurrently + }); + + // Event handlers + worker.on('completed', (job, result) => { + logger.info('Page save job completed', { + jobId: job.id, + pageId: result.pageId, + duration: job.processedOn ? Date.now() - job.processedOn : 'N/A', + }); + }); + + worker.on('failed', (job, err) => { + logger.error('Page save job failed permanently', { + jobId: job?.id, + pageId: job?.data?.pageId, + error: err.message, + attemptsMade: job?.attemptsMade, + }); + }); + + worker.on('error', (err) => { + logger.error('Page save worker error:', err); + }); + + logger.info('✅ Page save worker started'); + return worker; +}; + +export default createPageSaveWorker; diff --git a/backend/src/workers/taskReminder.worker.js b/backend/src/workers/taskReminder.worker.js new file mode 100644 index 0000000..3aeae0d --- /dev/null +++ b/backend/src/workers/taskReminder.worker.js @@ -0,0 +1,146 @@ +/** + * Task Reminder Worker + * @description BullMQ worker for processing task reminder operations + */ + +import { Worker } from 'bullmq'; +import config from '../config/index.js'; +import logger from '../utils/logger.js'; +import TaskModel from '../models/Task.model.js'; +import { + sendTaskReminderEmail, + sendTaskOverdueEmail, +} from '../controllers/v1/mailer.controller.js'; + +/** + * Redis connection configuration + */ +const redisConnection = { + host: config.redis.host, + port: config.redis.port, + maxRetriesPerRequest: null, +}; + +/** + * Process task reminder job + * @param {object} job - BullMQ job + * @returns {object} Reminder result + */ +const processTaskReminder = async (job) => { + const { checkType = 'all' } = job.data; + + logger.info('Processing task reminders', { + jobId: job.id, + checkType, + attemptsMade: job.attemptsMade, + }); + + try { + const now = new Date(); + const oneHourFromNow = new Date(now.getTime() + 60 * 60 * 1000); + const oneHourWindow = 5 * 60 * 1000; + + let oneHourReminders = 0; + let overdueReminders = 0; + + // Check 1-hour reminders + if (checkType === 'all' || checkType === 'one-hour') { + const tasksNearing1Hour = await TaskModel.find({ + taskDeadline: { + $gte: new Date(oneHourFromNow.getTime() - oneHourWindow), + $lte: new Date(oneHourFromNow.getTime() + oneHourWindow), + }, + isTaskCompleted: false, + oneHourReminderSent: false, + }).populate('owner'); + + for (const task of tasksNearing1Hour) { + logger.info( + `Sending 1-hour reminder for task: ${task.taskName} to user: ${task.owner.email}` + ); + const emailResult = await sendTaskReminderEmail(task, '1 hour'); + if (emailResult.success) { + await TaskModel.findByIdAndUpdate(task._id, { oneHourReminderSent: true }); + oneHourReminders++; + } + } + } + + // Check overdue reminders + if (checkType === 'all' || checkType === 'overdue') { + const overdueTasks = await TaskModel.find({ + taskDeadline: { $lt: now }, + isTaskCompleted: false, + overdueReminderSent: false, + }).populate('owner'); + + for (const task of overdueTasks) { + logger.info( + `Sending overdue reminder for task: ${task.taskName} to user: ${task.owner.email}` + ); + const emailResult = await sendTaskOverdueEmail(task); + if (emailResult.success) { + await TaskModel.findByIdAndUpdate(task._id, { overdueReminderSent: true }); + overdueReminders++; + } + } + } + + logger.info('Task reminders completed successfully', { + jobId: job.id, + oneHourReminders, + overdueReminders, + }); + + return { + success: true, + oneHourReminders, + overdueReminders, + }; + } catch (error) { + logger.error('Task reminder processing failed', { + jobId: job.id, + error: error.message, + attemptsMade: job.attemptsMade, + }); + throw error; // Will trigger retry if attempts remain + } +}; + +/** + * Create and start the task reminder worker + * @returns {Worker} BullMQ worker instance + */ +export const createTaskReminderWorker = () => { + const worker = new Worker('task-reminder', processTaskReminder, { + connection: redisConnection, + concurrency: 1, // Process one reminder job at a time + }); + + // Event handlers + worker.on('completed', (job, result) => { + logger.info('Task reminder job completed', { + jobId: job.id, + oneHourReminders: result.oneHourReminders, + overdueReminders: result.overdueReminders, + duration: job.processedOn ? Date.now() - job.processedOn : 'N/A', + }); + }); + + worker.on('failed', (job, err) => { + logger.error('Task reminder job failed permanently', { + jobId: job?.id, + error: err.message, + attemptsMade: job?.attemptsMade, + }); + }); + + worker.on('error', (err) => { + logger.error('Task reminder worker error:', err); + }); + + logger.info('✅ Task reminder worker started'); + return worker; +}; + +export default createTaskReminderWorker; diff --git a/docker-compose.yml b/docker-compose.yml index 5eeb5e4..cdcd34d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,15 +5,14 @@ services: image: ghcr.io/braydenidzenga/zettanote-nginx:latest container_name: zettanote-nginx ports: - - '80:80' - - '443:443' + - "80:80" + - "443:443" volumes: - nginx_certbot:/etc/letsencrypt - nginx_certbot:/var/www/certbot depends_on: - frontend - backend - - motia restart: unless-stopped networks: - zettanote-network @@ -22,7 +21,7 @@ services: image: ghcr.io/braydenidzenga/zettanote-backend:latest container_name: zettanote-backend expose: - - '4000' + - "4000" environment: - NODE_ENV=production - PORT=4000 @@ -43,38 +42,20 @@ services: - CLOUDINARY_SECRET=${CLOUDINARY_SECRET} - DISABLE_REMINDER_CRON=${DISABLE_REMINDER_CRON} - DISABLE_IMAGE_CLEANUP_CRON=${DISABLE_IMAGE_CLEANUP_CRON} - - USE_MOTIA=true - - MOTIA_URL=http://zettanote-motia:3001 depends_on: - mongodb - redis - - motia restart: unless-stopped healthcheck: test: - ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:4000/api/health'] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s - networks: - - zettanote-network - - motia: - image: ghcr.io/braydenidzenga/zettanote-motia:latest - container_name: zettanote-motia - expose: - - '3001' - environment: - - NODE_ENV=production - - MOTIA_PORT=3001 - - BACKEND_URL=http://zettanote-backend:4000 - - REDIS_URL=redis://zettanote-redis:6379 - depends_on: - - redis - restart: unless-stopped - healthcheck: - test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:3001/health'] + [ + "CMD", + "wget", + "--no-verbose", + "--tries=1", + "--spider", + "http://localhost:4000/api/health", + ] interval: 30s timeout: 10s retries: 3 @@ -86,7 +67,7 @@ services: image: ghcr.io/braydenidzenga/zettanote-frontend:latest container_name: zettanote-frontend expose: - - '3000' + - "3000" environment: - NODE_ENV=production - PORT=3000 @@ -95,7 +76,15 @@ services: - backend restart: unless-stopped healthcheck: - test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:3000/'] + test: + [ + "CMD", + "wget", + "--no-verbose", + "--tries=1", + "--spider", + "http://localhost:3000/", + ] interval: 30s timeout: 10s retries: 3 @@ -105,11 +94,11 @@ services: redis: image: redis:7.0-alpine container_name: zettanote-redis - expose: - - '6379' + ports: + - "6379:6379" restart: unless-stopped healthcheck: - test: ['CMD', 'redis-cli', 'ping'] + test: ["CMD", "redis-cli", "ping"] interval: 30s timeout: 10s retries: 3 @@ -126,10 +115,10 @@ services: volumes: - mongodb_data:/data/db expose: - - '27017' + - "27017" restart: unless-stopped healthcheck: - test: ['CMD', 'mongosh', '--eval', 'db.adminCommand("ping")'] + test: ["CMD", "mongosh", "--eval", 'db.adminCommand("ping")'] interval: 30s timeout: 10s retries: 3 diff --git a/docs/backend.md b/docs/backend.md index 0326213..2e02a85 100644 --- a/docs/backend.md +++ b/docs/backend.md @@ -26,6 +26,7 @@ ZettaNote Backend is a robust Node.js/Express API server that powers the note-ta - **Repository Pattern**: Data access abstraction - **Service Layer**: Business logic encapsulation - **Error Handling**: Centralized error management +- **Background Jobs**: BullMQ for asynchronous task processing ## Project Structure @@ -37,7 +38,9 @@ backend/ │ │ ├── database.js # MongoDB connection setup │ │ ├── redis.js # Redis connection setup │ │ ├── passport.js # OAuth authentication setup -│ │ └── cors.js # CORS configuration +│ │ ├── cors.js # CORS configuration +│ │ ├── queue.js # BullMQ queue configuration +│ │ └── schedulers.js # BullMQ scheduled jobs │ │ │ ├── controllers/ # Request handlers │ │ ├── auth.controller.js # Authentication logic @@ -78,8 +81,15 @@ backend/ │ │ ├── messages.js # Response messages │ │ └── statusCodes.js # HTTP status codes │ │ -│ ├── jobs/ # Background jobs -│ │ └── reminderJob.js # Reminder notifications +│ ├── jobs/ # Background jobs (legacy cron) +│ │ ├── reminderJob.js # Reminder notifications +│ │ └── imageCleanupJob.js # Image cleanup tasks +│ │ +│ ├── workers/ # BullMQ workers +│ │ ├── pageSave.worker.js # Page save processing +│ │ ├── imageUpload.worker.js # Image upload processing +│ │ ├── imageCleanup.worker.js # Image cleanup processing +│ │ └── taskReminder.worker.js # Task reminder processing │ │ │ ├── mailers/ # Email service clients │ │ └── resend.client.js # Resend API client @@ -345,12 +355,27 @@ const sendEmail = async (to, subject, html, text) => { ## Background Jobs -### Reminder System +ZettaNote uses **BullMQ** for reliable background job processing. See [BullMQ Documentation](./bullmq-jobs.md) for detailed information. + +### Job Types + +1. **Page Save Jobs**: Asynchronous page content updates +2. **Image Upload Jobs**: Background image processing and Cloudinary uploads +3. **Image Cleanup Jobs**: Orphaned image detection and deletion +4. **Task Reminder Jobs**: Email notifications for upcoming/overdue tasks + +### Scheduled Tasks + +- **Image Cleanup**: Runs every 6 hours +- **Task Reminders**: Runs every 5 minutes + +### Features -- Cron-based task scheduling -- Automated email reminders -- Task completion notifications -- Maintenance cleanup jobs +- **Automatic Retries**: Failed jobs retry with exponential backoff +- **Job Persistence**: Jobs survive application restarts +- **Concurrency Control**: Process multiple jobs simultaneously +- **Job Monitoring**: Track job status and metrics +- **Graceful Shutdown**: Properly close workers on server shutdown ## Testing Strategy diff --git a/docs/bullmq-jobs.md b/docs/bullmq-jobs.md new file mode 100644 index 0000000..3762cae --- /dev/null +++ b/docs/bullmq-jobs.md @@ -0,0 +1,380 @@ +# Background Job Processing with BullMQ + +## Overview + +ZettaNote uses **BullMQ** for reliable background job processing. BullMQ is a fast, robust queue system based on Redis that handles asynchronous tasks like image uploads, page saves, image cleanup, and task reminders. + +## Architecture + +### Why BullMQ? + +- **Redis-based**: Built on top of Redis for speed and reliability +- **Job Persistence**: Jobs are persisted to Redis, surviving application restarts +- **Retry Logic**: Automatic retry with exponential backoff for failed jobs +- **Concurrency Control**: Process multiple jobs concurrently with configurable limits +- **Monitoring**: Built-in job status tracking and metrics +- **Scheduled Jobs**: Support for cron-like repeatable jobs + +### Components + +1. **Queues**: Manage job storage and distribution +2. **Workers**: Process jobs from queues +3. **Schedulers**: Set up repeatable/cron-based jobs + +## Queue Configuration + +Located in `backend/src/config/queue.js`, we define four queues: + +### 1. Page Save Queue + +- **Purpose**: Process page content updates asynchronously +- **Concurrency**: 5 workers +- **Jobs**: Update page content, manage image references, invalidate caches + +### 2. Image Upload Queue + +- **Purpose**: Handle image uploads to Cloudinary +- **Concurrency**: 3 workers +- **Jobs**: Upload images, save metadata to database + +### 3. Image Cleanup Queue + +- **Purpose**: Clean up orphaned and marked images +- **Concurrency**: 1 worker (to avoid conflicts) +- **Jobs**: Mark orphaned images, delete marked images from Cloudinary + +### 4. Task Reminder Queue + +- **Purpose**: Send email reminders for upcoming/overdue tasks +- **Concurrency**: 1 worker +- **Jobs**: Check deadlines, send email notifications + +## Workers + +Workers are implemented in `backend/src/workers/`: + +### Page Save Worker (`pageSave.worker.js`) + +```javascript +// Processes page save operations +- Update page content in MongoDB +- Track image references (added/removed) +- Update Redis cache +- Invalidate related user caches +``` + +### Image Upload Worker (`imageUpload.worker.js`) + +```javascript +// Handles image uploads +- Upload to Cloudinary with unique identifiers +- Save metadata to MongoDB +- Track page associations +``` + +### Image Cleanup Worker (`imageCleanup.worker.js`) + +```javascript +// Manages image lifecycle +- Mark orphaned images (no page references) +- Delete marked images from Cloudinary and database +- Process in configurable batch sizes +``` + +### Task Reminder Worker (`taskReminder.worker.js`) + +```javascript +// Sends task notifications +- Find tasks due in 1 hour (±5 minute window) +- Find overdue tasks +- Send email reminders via Resend API +- Update reminder flags in database +``` + +## Scheduled Jobs + +Configured in `backend/src/config/schedulers.js`: + +### Image Cleanup Schedule + +- **Frequency**: Every 6 hours (`0 */6 * * *`) +- **Job Type**: Comprehensive cleanup (orphaned detection + marked deletion) +- **Batch Size**: 50 images per run +- **Initial Run**: On server startup + +### Task Reminder Schedule + +- **Frequency**: Every 5 minutes (`*/5 * * * *`) +- **Job Type**: Check all tasks for upcoming deadlines and overdue status +- **Initial Run**: On server startup + +## Job Configuration + +### Default Options + +```javascript +{ + attempts: 3, // Retry failed jobs up to 3 times + backoff: { + type: 'exponential', + delay: 5000 // Start with 5 second delay + }, + removeOnComplete: { + age: 86400, // Keep completed jobs for 24 hours + count: 1000 // Keep last 1000 completed jobs + }, + removeOnFail: { + age: 604800, // Keep failed jobs for 7 days + count: 5000 + } +} +``` + +## Usage Examples + +### Adding a Page Save Job + +```javascript +import { pageSaveQueue } from './config/queue.js'; + +// Queue a page save job +const job = await pageSaveQueue.add('page-save', { + pageId: '507f1f77bcf86cd799439011', + newPageData: '# My Note\nContent here...', + userId: '507f1f77bcf86cd799439012', +}); + +// Returns job ID for tracking +console.log('Job queued with ID:', job.id); +``` + +### Adding an Image Upload Job + +```javascript +import { imageUploadQueue } from './config/queue.js'; + +const job = await imageUploadQueue.add('image-upload', { + image: base64ImageData, + originalName: 'photo.jpg', + pageId: '507f1f77bcf86cd799439011', + userId: '507f1f77bcf86cd799439012', +}); +``` + +### Manual Image Cleanup Trigger + +```javascript +import { imageCleanupQueue } from './config/queue.js'; + +await imageCleanupQueue.add('manual-cleanup', { + cleanupType: 'comprehensive', // 'mark-orphaned' | 'cleanup-marked' | 'comprehensive' + batchSize: 100, +}); +``` + +## Monitoring + +### Job States + +- **waiting**: Job is in queue, waiting to be processed +- **active**: Job is currently being processed +- **completed**: Job finished successfully +- **failed**: Job failed (will retry if attempts remaining) +- **delayed**: Job is delayed for retry + +### Event Listeners + +Workers emit events for monitoring: + +```javascript +worker.on('completed', (job, result) => { + logger.info('Job completed', { jobId: job.id, result }); +}); + +worker.on('failed', (job, err) => { + logger.error('Job failed', { jobId: job.id, error: err.message }); +}); + +worker.on('error', (err) => { + logger.error('Worker error', { error: err }); +}); +``` + +## Error Handling + +### Automatic Retries + +- Failed jobs are automatically retried up to 3 times +- Exponential backoff: 5s, 10s, 20s delays +- After all attempts fail, job moves to 'failed' state + +### Job Failures + +Common failure scenarios and handling: + +1. **Database Connection Issues** + - Job will retry automatically + - Check MongoDB connection health + - Review connection pool settings + +2. **External API Failures** (Cloudinary, Resend) + - Retry with exponential backoff + - Check API credentials and quotas + - Monitor external service status + +3. **Data Validation Errors** + - Job fails immediately (no retry) + - Log detailed error information + - Fix data issues at source + +## Configuration + +### Environment Variables + +```bash +# Redis connection for BullMQ +REDIS_URL=redis://localhost:6379 + +# Disable scheduled jobs if needed +DISABLE_REMINDER_CRON=false +DISABLE_IMAGE_CLEANUP_CRON=false +``` + +### Redis Connection + +BullMQ uses Redis connection configured in `backend/src/config/index.js`: + +```javascript +redis: { + url: process.env.REDIS_URL || 'redis://localhost:6379', + host: 'localhost', // Parsed from URL + port: 6379 // Parsed from URL +} +``` + +## Server Integration + +Workers and schedulers are initialized in `backend/server.js`: + +```javascript +// Initialize queues +await initializeQueues(); + +// Start workers +const workers = { + pageSave: createPageSaveWorker(), + imageUpload: createImageUploadWorker(), + imageCleanup: createImageCleanupWorker(), + taskReminder: createTaskReminderWorker(), +}; + +// Initialize scheduled jobs +await initializeScheduledJobs(); +``` + +### Graceful Shutdown + +Workers and queues are properly closed on server shutdown: + +```javascript +// Close workers +await Promise.all([ + workers.pageSave.close(), + workers.imageUpload.close(), + workers.imageCleanup.close(), + workers.taskReminder.close(), +]); + +// Close queues +await closeQueues(); +``` + +## Performance Tuning + +### Concurrency Settings + +Adjust worker concurrency based on your server resources: + +```javascript +// High-traffic page saves +const worker = new Worker('page-save', processPageSave, { + connection: redisConnection, + concurrency: 10, // Process 10 jobs simultaneously +}); + +// Resource-intensive image uploads +const worker = new Worker('image-upload', processImageUpload, { + connection: redisConnection, + concurrency: 3, // Limit concurrent uploads +}); +``` + +### Redis Memory + +Monitor Redis memory usage: + +- Completed jobs are auto-removed after 24 hours +- Failed jobs kept for 7 days for debugging +- Adjust retention policies based on volume + +## Troubleshooting + +### Common Issues + +1. **Jobs Stuck in Queue** + - Check if workers are running + - Verify Redis connectivity + - Review worker error logs + +2. **High Memory Usage** + - Check job retention settings + - Monitor queue sizes + - Adjust cleanup policies + +3. **Slow Job Processing** + - Increase worker concurrency + - Optimize job processing logic + - Check database/external API performance + +### Debug Commands + +```bash +# Monitor Redis queue keys +redis-cli KEYS "bull:*" + +# Check queue lengths +redis-cli LLEN "bull:page-save:wait" + +# View job details +redis-cli HGETALL "bull:page-save:job-id" +``` + +## Migration from Motia + +ZettaNote previously used Motia for background tasks. BullMQ provides: + +- **Better reliability**: Redis-backed persistence +- **Simpler deployment**: No separate service needed +- **Better monitoring**: Built-in job status tracking +- **More flexible**: Standard Node.js patterns +- **Cost effective**: Runs in main backend process + +All Motia functionality has been migrated to BullMQ workers with equivalent or improved capabilities. + +## Best Practices + +1. **Keep Jobs Small**: Break large tasks into smaller jobs +2. **Idempotent Jobs**: Ensure jobs can be safely retried +3. **Timeout Handling**: Set appropriate job timeouts +4. **Monitor Job Metrics**: Track completion rates and failures +5. **Test Locally**: Use Redis locally for development +6. **Graceful Degradation**: Handle queue failures gracefully + +## Future Enhancements + +- **Job Prioritization**: High-priority jobs processed first +- **Rate Limiting**: Limit job processing rates +- **Job Chaining**: Sequential job dependencies +- **Progress Tracking**: Real-time job progress updates +- **Admin Dashboard**: Web UI for job monitoring +- **Metrics Export**: Prometheus/Grafana integration diff --git a/motia/.cursor/architecture/architecture.mdc b/motia/.cursor/architecture/architecture.mdc deleted file mode 100644 index d300e22..0000000 --- a/motia/.cursor/architecture/architecture.mdc +++ /dev/null @@ -1,96 +0,0 @@ ---- -description: How to structure your Motia project -globs: -alwaysApply: true ---- - -# Architecture Guide - -## Overview - -This guide covers the architecture of a Motia project. - -## File Structure - -All step files should be underneath the `steps/` folder. - -Underneath the `steps/` folder, create subfolders for Flows. Flows are used to group steps together. - -## Step Naming Conventions - -### Typescript - -- Use kebab-case for filenames: `resource-processing.step.ts` -- Include `.step` before language extension - -### Python - -- Use snake_case for filenames: `data_processor_step.py` -- Include `_step` before language extension - -### Global - -- Match handler names to config names -- Use descriptive, action-oriented names - -## Code Style Guidelines - -- **JavaScript**: Use modern ES6+ features, async/await, proper error handling -- **TypeScript**: Make sure you use the correct Handlers type that is auto generated on the `types.d.ts` file. - -## Defining Middlewares - -Middleware is a powerful feature in Motia to help adding common validation, error -handling and other common logic to your steps. - -- Make sure to add all the middlewares in a single folder, called `middlewares/`. -- Create a comprehensive file name for the middleware, like `auth.middleware.ts`. -- Follow SOLID principles with separation of concerns in middlewares, create a middleware for each responsibility. -- Use core middleware to handle ZodError gracefully (see [Error Handling Guide](./error-handling.mdc)) -- Rate limiting and CORS are not needed to be handled in middleware since they're an infrastructure concern. - -## Domain Driven Design - -Make sure you follow Domain Driven Design principles in your project. - -- Create `/src/services` folder to store your services, this is where it holds business logic. -- Create `/src/repositories` folder to store your repositories, this is where it holds data access logic. -- Create `/src/utils` folder to store your utility functions. -- Models and DTOs are not quite necessary, we can rely on zod to create the models and DTOs from the steps. -- Controller layer is the Steps, it should have mostly logic around validation and calling services. -- Avoid having Service methods with just a call to the Repository, it should have some logic around it, if it doesn't have, then Steps can have access to repositories directly. - -### Services - -Defining services can be done in the following way: - -- Create a folder underneath `/src/services/` folder, like `/src/services/auth/`. -- Create a file inside the folder called `index.ts`. -- Inside `index.ts`, export a constant with the name of the service, with the methods as properties. -- Methods should be defined as separate files, use export named functions. -- Use the service in the Steps. - -#### Example - -```typescript -/** - * Business logic for authentication defined in a separate file in the same folder. - */ -import { login } from './login' - -/** - * Constant with the name of the service, with the methods as properties. - */ -export const authService = { - login -} -``` - -## Logging and observability - -- Make sure to use the Logger from Motia (from context object) to log messages. -- Make sure to have visibility of what is going on in a request -- Before throwing errors, make sure to log the issue, identify if issue is a validation blocker, then log with `logger.warn`, if it's something that is not supposed to happen, then log with `logger.error`. -- Make sure to add context to the logs to help identify any potential issues. - - diff --git a/motia/.cursor/architecture/error-handling.mdc b/motia/.cursor/architecture/error-handling.mdc deleted file mode 100644 index 1976317..0000000 --- a/motia/.cursor/architecture/error-handling.mdc +++ /dev/null @@ -1,122 +0,0 @@ ---- -description: How to handle errors in a Motia project -globs: -alwaysApply: true ---- - -# Error Handling Guide - -Errors happen, but we need to handle them gracefully. Make sure you create a custom error class for your project, underneath `/src/errors/` folder. - -## Good practices - -- Use Custom error to return errors to the client. -- Anything that is not the error class, should be logged with `logger.error`. And root cause should be omitted to the client. - -## Create a custom Error class - -Name: `/src/errors/base.error.ts` - -```typescript -export class BaseError extends Error { - public readonly status: number - public readonly code: string - public readonly metadata: Record - - constructor( - message: string, - status: number = 500, - code: string = 'INTERNAL_SERVER_ERROR', - metadata: Record = {} - ) { - super(message) - this.name = this.constructor.name - this.status = status - this.code = code - this.metadata = metadata - - // Maintains proper stack trace for where our error was thrown - Error.captureStackTrace(this, this.constructor) - } - - toJSON() { - return { - error: { - name: this.name, - message: this.message, - code: this.code, - status: this.status, - ...(Object.keys(this.metadata).length > 0 && { metadata: this.metadata }), - }, - } - } -} -``` - -Then create sub class for specific errors that are commonly thrown in your project. - -Name: `/src/errors/not-found.error.ts` - -```typescript -import { BaseError } from './base.error' - -export class NotFoundError extends BaseError { - constructor(message: string = 'Not Found', metadata: Record = {}) { - super(message, 404, 'NOT_FOUND', metadata) - } -} -``` - -## Core Middleware - -Make sure you create a core middleware that will be added to ALL API Steps. - -File: `/src/middlewares/core.middleware.ts` - -```typescript -import { ApiMiddleware } from 'motia' -import { ZodError } from 'zod' -import { BaseError } from '../errors/base.error' - -export const coreMiddleware: ApiMiddleware = async (req, ctx, next) => { - const logger = ctx.logger - - try { - return await next() - } catch (error: any) { - if (error instanceof ZodError) { - logger.error('Validation error', { - error, - stack: error.stack, - errors: error.errors, - }) - - return { - status: 400, - body: { - error: 'Invalid request body', - data: error.errors, - }, - } - } else if (error instanceof BaseError) { - logger.error('BaseError', { - status: error.status, - code: error.code, - metadata: error.metadata, - name: error.name, - message: error.message, - }) - - return { status: error.status, body: error.toJSON() } - } - - logger.error('Error while performing request', { - error, - body: req.body, - stack: error.stack, - }) - - return { status: 500, body: { error: 'Internal Server Error' } } - } -} -``` \ No newline at end of file diff --git a/motia/.cursor/index.mdc b/motia/.cursor/index.mdc deleted file mode 100644 index 1c25315..0000000 --- a/motia/.cursor/index.mdc +++ /dev/null @@ -1,34 +0,0 @@ ---- -description: Rules for the project -globs: -alwaysApply: true ---- - -## Real time events - -Make sure to use [real time events guide](./rules/motia/realtime-streaming.mdc) to create a new real time event. - -## State/Cache management - -Make sure to use [state management guide](./rules/motia/state-management.mdc) to create a new state management. - -## Creating HTTP Endpoints - -Make sure to use [API steps guide](./rules/motia/api-steps.mdc) to create new HTTP endpoints. - -## Background Tasks - -Make sure to use [event steps guide](./rules/motia/event-steps.mdc) to create new background tasks. - -## Scheduled Tasks - -Make sure to use [cron steps guide](./rules/motia/cron-steps.mdc) to create new scheduled tasks. - -## Virtual Steps & Flow Visualization - -Make sure to use [virtual steps guide](./rules/motia/virtual-steps.mdc) when connecting nodes virtually and creating smooth flows in Workbench. - -## Authentication - -If ever need to add authentication, make sure to use middleware to authenticate the request. -Make sure to use [middlewares](./rules/motia/middlewares.mdc) to validate the requests. diff --git a/motia/.cursor/rules/motia/api-steps.mdc b/motia/.cursor/rules/motia/api-steps.mdc deleted file mode 100644 index c687959..0000000 --- a/motia/.cursor/rules/motia/api-steps.mdc +++ /dev/null @@ -1,425 +0,0 @@ ---- -description: How to create HTTP endpoints in Motia -globs: steps/**/*.step.ts,steps/**/*.step.js,steps/**/*_step.py -alwaysApply: false ---- -# API Steps Guide - -API Steps expose HTTP endpoints that can trigger workflows and emit events. - -## Creating API Steps - -Steps need to be created in the `steps` folder, it can be in subfolders. - -- Steps in TS and JS should end with `.step.ts` and `.step.js` respectively. -- Steps in Python should end with `_step.py`. - -## Definition - -Defining an API Step is done by two elements. Configuration and Handler. - -### Schema Definition - -- **TypeScript/JavaScript**: Motia uses Zod schemas for automatic validation of request/response data -- **Python**: Motia uses JSON Schema format. You can optionally use Pydantic models to generate JSON Schemas and handle manual validation in your handlers - -### Configuration - -**TypeScript/JavaScript**: You need to export a config constant via `export const config` that is a `ApiRouteConfig` type. - -**Python**: You need to define a `config` dictionary with the same properties as the TypeScript `ApiRouteConfig`. - -```typescript -export type Emit = string | { - /** - * The topic name to emit to. - */ - topic: string; - - /** - * Optional label for the emission, could be used for documentation or UI. - */ - label?: string; - - /** - * This is purely for documentation purposes, - * it doesn't affect the execution of the step. - * - * In Workbench, it will render differently based on this value. - */ - conditional?: boolean; -} - -export interface QueryParam { - /** - * The name of the query parameter - */ - name: string - /** - * The description of the query parameter - */ - description: string -} - -export interface ApiRouteConfig { - /** - * Should always be api - */ - type: 'api' - - /** - * A unique name for this API step, used internally and for linking handlers. - */ - name: string - - /** - * Optional human-readable description. - */ - description?: string - - /** - * The URL path for this API endpoint (e.g., '/users/:id'). - */ - path: string - - /** - * The HTTP method for this route. - * POST, GET, PUT, DELETE, PATCH, OPTIONS, HEAD - */ - method: ApiRouteMethod - - /** - * Topics this API step can emit events to. - * Important note: All emits in the handler need to be listed here. - */ - emits: Emit[] - - /** - * Optional: Topics that are virtually emitted, perhaps for documentation or lineage, - * but not strictly required for execution. - * - * In Motia Workbench, they will show up as gray connections to other steps. - */ - virtualEmits?: Emit[] - - /** - * Optional: Virtually subscribed topics. - * - * Used by API steps when we want to chain different HTTP requests - * that could happen sequentially - */ - virtualSubscribes?: string[] - /** - * Flows are used to group multiple steps to be visible in diagrams in Workbench - */ - flows?: string[] - - /** - * List of middlewares that will be executed BEFORE the handler is called - */ - middleware?: ApiMiddleware[] - - /** - * Defined with Zod library, can be a ZodObject OR a ZodArray. - * - * Note: This is not validated automatically, you need to validate it in the handler. - */ - bodySchema?: ZodInput - - /** - * Defined with Zod library, can be a ZodObject OR a ZodArray - * - * The key (number) is the HTTP status code this endpoint can return and - * for each HTTP Status Code, you need to define a Zod schema that defines the response body - */ - responseSchema?: Record - - /** - * Mostly for documentation purposes, it will show up in Endpoints section in Workbench - */ - queryParams?: QueryParam[] - - /** - * Files to include in the step bundle. - * Needs to be relative to the step file. - */ - includeFiles?: string[] -} -``` - -### Handler - -The handler is a function that is exported via `export const handler` that is a `ApiRouteHandler` type. - -#### Type Definition from Motia - -```typescript -export interface ApiRequest { - /** - * Key-value pairs of path parameters (e.g., from '/users/:id'). - */ - pathParams: Record - /** - * Key-value pairs of query string parameters. Values can be string or array of strings. - */ - queryParams: Record - /** - * The parsed request body (typically an object if JSON, but can vary). - */ - body: TBody - /** - * Key-value pairs of request headers. Values can be string or array of strings. - */ - headers: Record -} - -export type ApiRouteHandler< - /** - * The type defined by config['bodySchema'] - */ - TRequestBody = unknown, - /** - * The type defined by config['responseSchema'] - */ - TResponseBody extends ApiResponse = ApiResponse, - /** - * The type defined by config['emits'] which is dynamic depending - * on the topic handlers (Event Steps) - */ - TEmitData = never, -> = (req: ApiRequest, ctx: FlowContext) => Promise -``` - -### Handler definition - -**TypeScript/JavaScript:** -```typescript -export const handler: Handlers['CreateResource'] = async (req, { emit, logger, state, streams }) => { - // Implementation -} -``` - -**Python:** -```python -async def handler(req, context): - # req: dictionary containing pathParams, queryParams, body, headers - # context: object containing emit, logger, state, streams, trace_id - pass -``` - -### Examples - -#### TypeScript Example - -```typescript -import { ApiRouteConfig, Handlers } from 'motia'; -import { z } from 'zod'; - -const bodySchema = z.object({ - title: z.string().min(1, "Title cannot be empty"), - description: z.string().optional(), - category: z.string().min(1, "Category is required"), - metadata: z.record(z.any()).optional() -}) - -export const config: ApiRouteConfig = { - type: 'api', - name: 'CreateResource', - path: '/resources', - method: 'POST', - emits: ['send-email'], - flows: ['resource-management'], - bodySchema, - responseSchema: { - 201: z.object({ - id: z.string(), - title: z.string(), - category: z.string() - }), - 400: z.object({ error: z.string() }) - } -}; - -export const handler: Handlers['CreateResource'] = async (req, { emit, logger }) => { - try { - const { title, description, category, metadata } = bodySchema.parse(req.body); - - // Use the logger for structured logging. It's good practice to log key events or data. - logger.info('Attempting to create resource', { title, category }); - - /** - * Create files to manage service calls. - * - * Let's try to use Domain Driven Design to create files to manage service calls. - * Steps are the entry points, they're the Controllers on the DDD architecture. - */ - const result = await service.createResource(resourceData); - - /** - * This is how we emit events to trigger Event Steps. - * Only use emits if the task can take a while to complete. - * - * Examples of long tasks are: - * - LLM Calls - * - Processing big files, like images, videos, audio, etc. - * - Sending emails - * - * Other applicable examples are tasks that are likely to fail, examples: - * - Webhook call to external systems - * - * API Calls that are okay to fail gracefully can be done without emits. - */ - await emit({ - /** - * 'topic' must be one of the topics listed in config['emits']. - * do not emit to topics that are not defined in Steps - */ - topic: 'send-email', - /** - * 'data' is the payload of the event message. - * make sure the data used is compliant with the Event Step input schema - */ - data: { - /** - * The data to send to the Event Step. - */ - resource: result, - /** - * The user to send the email to. - */ - user - } - }); - - logger.info('Resource created successfully', { resourceId, title, category }); - - // Return a response object for the HTTP request. - return { - status: 201, // CREATED (specified in config['responseSchema']) - /** - * 'body' is the JSON response body sent back to the client. - */ - body: { - id: result.id, - title: result.title, - category: result.category, - status: 'active' - } - }; - } catch (error) { - /** - * For one single step project, it is fine to - * handle ZodErrors here, on multiple steps projects, - * it is highly recommended to handle them as a middleware - * (defined in config['middleware']) - */ - if (error instanceof ZodError) { - logger.error('Resource creation failed', { error: error.message }); - return { - status: 400, - body: { error: 'Validation failed' } - }; - } - - logger.error('Resource creation failed', { error: error.message }); - return { - status: 500, - body: { error: 'Creation failed' } - }; - } -}; -``` - -#### Python Example - -```python -from pydantic import BaseModel, Field -from typing import Optional, Dict, Any - -class ResourceData(BaseModel): - title: str = Field(..., min_length=1, description="Title cannot be empty") - description: Optional[str] = None - category: str = Field(..., min_length=1, description="Category is required") - metadata: Optional[Dict[str, Any]] = None - -class ResourceResponse(BaseModel): - id: str - title: str - category: str - status: str - -class ErrorResponse(BaseModel): - error: str - -config = { - "type": "api", - "name": "CreateResource", - "path": "/resources", - "method": "POST", - "emits": ["send-email"], - "flows": ["resource-management"], - "bodySchema": ResourceData.model_json_schema(), - "responseSchema": { - 201: ResourceResponse.model_json_schema(), - 400: ErrorResponse.model_json_schema() - } -} - -async def handler(req, context): - try: - body = req.get("body", {}) - - # Optional: Validate input manually using Pydantic (Motia doesn't do this automatically) - resource_data = ResourceData(**body) - - context.logger.info("Attempting to create resource", { - "title": resource_data.title, - "category": resource_data.category - }) - - # Process the resource creation - result = await service.create_resource({ - "title": resource_data.title, - "description": resource_data.description, - "category": resource_data.category, - "metadata": resource_data.metadata - }) - - # Emit event to trigger other steps - await context.emit({ - "topic": "send-email", - "data": { - "resource": result, - "user_id": "example-user" - } - }) - - context.logger.info("Resource created successfully", { - "resource_id": result.get("id"), - "title": result.get("title"), - "category": result.get("category") - }) - - return { - "status": 201, - "body": { - "id": result.get("id"), - "title": result.get("title"), - "category": result.get("category"), - "status": "active" - } - } - - except ValidationError as e: - context.logger.error("Resource creation failed - Pydantic validation error", {"error": str(e)}) - return { - "status": 400, - "body": {"error": "Validation failed"} - } - except Exception as e: - context.logger.error("Resource creation failed", {"error": str(e)}) - return { - "status": 500, - "body": {"error": "Creation failed"} - } -``` \ No newline at end of file diff --git a/motia/.cursor/rules/motia/cron-steps.mdc b/motia/.cursor/rules/motia/cron-steps.mdc deleted file mode 100644 index a6e8458..0000000 --- a/motia/.cursor/rules/motia/cron-steps.mdc +++ /dev/null @@ -1,171 +0,0 @@ ---- -description: Cron Steps are scheduled tasks that run based on cron expressions. -globs: steps/**/*.step.ts,steps/**/*.step.js,steps/**/*_step.py -alwaysApply: false ---- -# Cron Steps Guide - -Cron Steps enable scheduled task execution using cron expressions. - -They're typically used for recurring jobs like nightly reports, data synchronization, etc. - -Cron steps can hold logic, but they do NOT have any retry mechanisms in place, if the logic -is likely to fail, it's recommended to use CRON Step to emit an event to a topic that will -ultimately trigger an Event Step that will handle the logic. - -## Creating Cron Steps - -Steps need to be created in the `steps` folder, it can be in subfolders. - -- Steps in TS and JS should end with `.step.ts` and `.step.js` respectively -- Steps in Python should end with `_step.py` - -## Definition - -Defining a CRON Step is done by two elements. Configuration and Handler. - -### Configuration - -**TypeScript/JavaScript**: You need to export a config constant via `export const config` that is a `CronConfig` type. - -**Python**: You need to define a `config` dictionary with the same properties as the TypeScript `CronConfig`. - -```typescript -export type Emit = string | { - /** - * The topic name to emit to. - */ - topic: string; - - /** - * Optional label for the emission, could be used for documentation or UI. - */ - label?: string; - - /** - * This is purely for documentation purposes, - * it doesn't affect the execution of the step. - * - * In Workbench, it will render differently based on this value. - */ - conditional?: boolean; - } - - -export type CronConfig = { - /** - * Should always be cron - */ - type: 'cron' - - /** - * A unique name for this cron step, used internally and for linking handlers. - */ - name: string - - /** - * Optional human-readable description. - */ - description?: string - - /** - * The cron expression for scheduling. - */ - cron: string - - /** - * Optional: Topics that are virtually emitted, perhaps for documentation or lineage, but not strictly required for execution. - */ - virtualEmits?: Emit[] - - /** - * Topics this cron step can emit events to. - */ - emits: Emit[] - - /** - * Optional: An array of flow names this step belongs to. - */ - flows?: string[] - - /** - * Files to include in the step bundle. - * Needs to be relative to the step file. - */ - includeFiles?: string[] -} -``` - -### Handler - -The handler is a function that is exported via `export const handler` that is a `CronHandler` type. - -**TypeScript/JavaScript:** -```typescript -/** - * CRON handler accepts only one argument, the FlowContext. - * - * The FlowContext is based on the Handlers which can vary depending on the config['emits']. - */ -export const handler: Handlers['CronJobEvery5Minutes'] = async ({ logger, emit, traceId, state, streams }) => { - logger.info('CRON Job Every 5 Minutes started') -} -``` - -**Python:** -```python -async def handler(context): - # context: object containing emit, logger, state, streams, trace_id - context.logger.info("CRON Job Every 5 Minutes started") -``` - -### Examples of Cron expressions - -- `0 0 * * *`: Runs daily at midnight -- `*/5 * * * *`: Runs every 5 minutes -- `0 9 * * *`: Runs daily at 9 AM -- `0 9 * * 1`: Runs every Monday at 9 AM -- `0 9 * * 1-5`: Runs every Monday to Friday at 9 AM - -### Example uses of Cron Steps - -- Sending email notifications on a regular basis -- Cleaning up old records -- Purging old data -- Generating reports -- Sending out scheduled notifications -- Collecting metrics from third-party services -- Reconciling data from different sources - -## Examples - -### TypeScript Example - -```typescript -export const config: CronConfig = { - type: 'cron', - name: 'CronJobEvery5Minutes', // should always be the same as Handlers['__'] - cron: '*/5 * * * *', - emits: [], // No emits in this example - flows: ['example-flow'] -}; - -export const handler: Handlers['CronJobEvery5Minutes'] = async ({ logger }) => { - logger.info('Cron job started') -} -``` - -### Python Example - -```python -config = { - "type": "cron", - "name": "CronJobEvery5Minutes", - "cron": "*/5 * * * *", # Run every 5 minutes - "emits": [], # No emits in this example - "flows": ["example-flow"] -} - -async def handler(context): - context.logger.info("Cron job started") -``` \ No newline at end of file diff --git a/motia/.cursor/rules/motia/event-steps.mdc b/motia/.cursor/rules/motia/event-steps.mdc deleted file mode 100644 index 8cc27e7..0000000 --- a/motia/.cursor/rules/motia/event-steps.mdc +++ /dev/null @@ -1,218 +0,0 @@ ---- -description: How to create background tasks in Motia -globs: steps/**/*.step.ts,steps/**/*.step.js,steps/**/*_step.py -alwaysApply: false ---- -# Event Steps Guide - -Event Steps are used to handle asynchronous events. These steps cannot be -invoked by a client or user. In order to ultimately trigger an Event Step, -you need to connect it to an API Step or a CRON Step. - -Examples of event steps are: -- LLM Calls -- Processing big files, like images, videos, audio, etc. -- Sending emails - -Other applicable examples are tasks that are likely to fail, examples: -- Webhook call to external systems - -## Creating Event Steps - -Steps need to be created in the `steps` folder, it can be in subfolders. - -- Steps in TS and JS should end with `.step.ts` and `.step.js` respectively. -- Steps in Python should end with `_step.py`. - -## Definition - -Defining an API Step is done by two elements. Configuration and Handler. - -### Schema Definition - -- **TypeScript/JavaScript**: Motia uses Zod schemas for automatic validation of input data -- **Python**: Motia uses JSON Schema format. You can optionally use Pydantic models to generate JSON Schemas and handle manual validation in your handlers - -### Configuration - -**TypeScript/JavaScript**: You need to export a config constant via `export const config` that is a `EventConfig` type. - -**Python**: You need to define a `config` dictionary with the same properties as the TypeScript `EventConfig`. - -```typescript -export type Emit = string | { - /** - * The topic name to emit to. - */ - topic: string; - - /** - * Optional label for the emission, could be used for documentation or UI. - */ - label?: string; - - /** - * This is purely for documentation purposes, - * it doesn't affect the execution of the step. - * - * In Workbench, it will render differently based on this value. - */ - conditional?: boolean; -} - -export type EventConfig = { - /** - * Should always be event - */ - type: 'event' - - /** - * A unique name for this event step, used internally and for linking handlers. - */ - name: string - - /** - * Optional human-readable description. - */ - description?: string - - /** - * An array of topic names this step listens to. - */ - subscribes: string[] - - /** - * An array of topics this step can emit events to. - */ - emits: Emit[] - - /** - * Optional: Topics that are virtually emitted, perhaps for documentation or lineage, but not strictly required for execution. - */ - virtualEmits?: Emit[] - - /** - * The Zod schema of the input data of events this step processes. - * - * This is used by Motia to create the correct types for whoever emits the event - * to this step. - * - * Avoid adding too much data to the input schema, only add the data that - * is necessary for the Event Step to process. If the data is too big it's - * recommended to store it in the state and fetch it from the state on the - * Event Step handler. - */ - input: ZodInput - - /** - * Optional: An array of flow names this step belongs to. - */ - flows?: string[] - /** - * Files to include in the step bundle. - * Needs to be relative to the step file. - */ - includeFiles?: string[] -} -``` - -### Handler - -The handler is a function that is exported via `export const handler` that is a `EventHandler` type. - -### Handler definition - -**TypeScript/JavaScript:** -```typescript -/** - * Input is inferred from the Event Step config['input'] - * Context is the FlowContext - */ -export const handler: Handlers['SendEmail'] = async (input, { emit, logger, state, streams }) => { - // Implementation -} -``` - -**Python:** -```python -async def handler(input_data, context): - # input_data: dictionary with the event data (matches the input schema) - # context: object containing emit, logger, state, streams, trace_id - pass -``` - -### Examples - -#### TypeScript Example - -```typescript -import { EventConfig, Handlers } from 'motia'; -import { z } from 'zod'; - -const inputSchema = z.object({ - email: z.string(), - templateId: z.string(), - templateData: z.record(z.string(), z.any()), -}) - -export const config: EventConfig = { - type: 'event', - name: 'SendEmail', - description: 'Sends email notification to the user', - subscribes: ['send-email'], - emits: [], - input: inputSchema, - flows: ['resource-management'] -}; - -export const handler: Handlers['SendEmail'] = async (input, { emit, logger }) => { - const { email, templateId, templateData } = input; - - // Process email sending logic here - await emailService.send({ - to: email, - templateId, - data: templateData - }); - - logger.info('Email sent successfully', { email, templateId }); -}; -``` - -#### Python Example - -```python -from pydantic import BaseModel -from typing import Dict, Any - -class EmailData(BaseModel): - email: str - template_id: str - template_data: Dict[str, Any] - -config = { - "type": "event", - "name": "SendEmail", - "description": "Sends email notification to the user", - "subscribes": ["send-email"], - "emits": [], - "input": EmailData.model_json_schema(), - "flows": ["resource-management"] -} - -async def handler(input_data, context): - # Optional: Validate input manually using Pydantic (Motia doesn't do this automatically) - email_data = EmailData(**input_data) - - # Process email sending logic here - await email_service.send({ - "to": email_data.email, - "template_id": email_data.template_id, - "data": email_data.template_data - }) - - context.logger.info("Email sent successfully", { - "email": email_data.email, - "template_id": email_data.template_id - }) -``` \ No newline at end of file diff --git a/motia/.cursor/rules/motia/middlewares.mdc b/motia/.cursor/rules/motia/middlewares.mdc deleted file mode 100644 index 153abeb..0000000 --- a/motia/.cursor/rules/motia/middlewares.mdc +++ /dev/null @@ -1,217 +0,0 @@ ---- -description: Middlewares are used to execute code before and after the handler is called -globs: steps/**/*.step.ts,steps/**/*.step.js,steps/**/*_step.py,middlewares/**/*.middleware.ts,middlewares/**/*.middleware.js,middlewares/**/*_middleware.py -alwaysApply: false ---- -# Middlewares Guide - -Middlewares are used to execute code before and after the handler is called in API Steps. - -The middleware is a handler that receives three arguments: -- **Request**: this is the same request object received by API Step handlers, if modified by the middleware, it will be the same object passed to the handler and any subsequent middleware. Be careful to not cause any side effects to the request object. -- **Context**: this is the same context object received by API Step handlers, if modified by the middleware, it will be the same object passed to the handler and any subsequent middleware. Be careful to not cause any side effects to the context object. -- **Next**: this is a function that you need to call to invoke the next middleware in the stack. If you don't call it, the request will be halted—the handler and any subsequent middlewares will not be called. - -## Next function - -Next function is a way to either continue the execution flow or stop it. For example, in authentication middlewares, if the user is not authenticated, you can return a 401 response and not call `next()`. - -It can also be used to enrich data returned back to the HTTP response. Like adding a header parameter or so after calling `next()`. - -## Adding middlewares to a step - -### TypeScript/JavaScript Example - -```typescript -import { ApiRouteConfig } from 'motia' -import { coreMiddleware } from '../middlewares/core.middleware' - -export const config: ApiRouteConfig = { - type: 'api', - name: 'SampleRoute', - description: 'Sample route', - path: '/sample', - method: 'GET', - emits: [], - flows: [], - middleware: [coreMiddleware], -} -``` - -### Python Example - -```python -async def enrich_data_middleware(req, context, next_fn): - context.logger.info("enriching data") - req["enriched"] = "yes" - return await next_fn() - -config = { - "type": "api", - "name": "SampleRoute", - "description": "Sample route", - "path": "/sample", - "method": "GET", - "emits": [], - "flows": [], - "middleware": [enrich_data_middleware], -} -``` - -## Middleware examples - -### Handling errors - -#### TypeScript/JavaScript - -```typescript -import { ApiMiddleware } from 'motia' - -export const coreMiddleware: ApiMiddleware = async (req, ctx, next) => { - const { logger } = ctx - - try { - /** - * Calling next() will invoke the next item in the stack. - * - * It will depend on the order of middlewares configured in the step, - * first one in the list is called first and so on. - */ - return await next() - } catch (error: any) { - logger.error('Error while performing request', { - error, - body: req.body, // make sure you don't include sensitive data in the logs - stack: error.stack, - }) - - return { - status: 500, - body: { error: 'Internal Server Error' }, - } - } -} -``` - -#### Python - -```python -async def error_handling_middleware(req, context, next_fn): - try: - # Calling next_fn() will invoke the next item in the stack. - # It will depend on the order of middlewares configured in the step, - # first one in the list is called first and so on. - return await next_fn() - except Exception as error: - context.logger.error('Error while performing request', { - 'error': str(error), - 'body': req.get('body'), # make sure you don't include sensitive data in the logs - }) - - return { - 'status': 500, - 'body': {'error': 'Internal Server Error'}, - } -``` - -### Enriching response - -#### TypeScript/JavaScript - -```typescript -export const enrichResponseMiddleware: ApiMiddleware = async (req, ctx, next) => { - const response = await next() - - response.headers['X-Custom-Header'] = 'Custom Value' - - return response -} -``` - -#### Python - -```python -async def enrich_response_middleware(req, context, next_fn): - response = await next_fn() - - if not response.get('headers'): - response['headers'] = {} - - response['headers']['X-Custom-Header'] = 'Custom Value' - - return response -``` - -### Handling validation errors - -#### TypeScript/JavaScript - Handling Zod Validation errors - -```typescript -import { ApiMiddleware } from 'motia' -import { ZodError } from 'zod' - -export const coreMiddleware: ApiMiddleware = async (req, ctx, next) => { - const logger = ctx.logger - - try { - return await next() - } catch (error: any) { - if (error instanceof ZodError) { - logger.error('Validation error', { - error, - stack: error.stack, - errors: error.errors, - }) - - return { - status: 400, - body: { - error: 'Invalid request body', - data: error.errors, - }, - } - } - - logger.error('Error while performing request', { - error, - body: req.body, // make sure you don't include sensitive data in the logs - stack: error.stack, - }) - - return { status: 500, body: { error: 'Internal Server Error' } } - } -} -``` - -#### Python - Handling Pydantic Validation errors - -```python -from pydantic import ValidationError - -async def validation_middleware(req, context, next_fn): - try: - return await next_fn() - except ValidationError as error: - context.logger.error('Validation error', { - 'error': str(error), - 'errors': error.errors(), - }) - - return { - 'status': 400, - 'body': { - 'error': 'Invalid request body', - 'data': error.errors(), - }, - } - except Exception as error: - context.logger.error('Error while performing request', { - 'error': str(error), - 'body': req.get('body'), # make sure you don't include sensitive data in the logs - }) - - return { - 'status': 500, - 'body': {'error': 'Internal Server Error'} - } -``` diff --git a/motia/.cursor/rules/motia/realtime-streaming.mdc b/motia/.cursor/rules/motia/realtime-streaming.mdc deleted file mode 100644 index a4f1c60..0000000 --- a/motia/.cursor/rules/motia/realtime-streaming.mdc +++ /dev/null @@ -1,380 +0,0 @@ ---- -description: Real-time streaming -globs: steps/**/*.step.ts,steps/**/*.step.js,steps/**/*_step.py,steps/**/*.stream.ts,steps/**/*.stream.js,steps/**/*_stream.py -alwaysApply: false ---- -# Real-time Streaming - -Building event driven applications often requires some real-time streaming capabilities. -- Like integration with LLMs, they should be implemented in an asynchronous way and updates should come in real-time. -- Chat applications, real-time collaboration, etc. -- Long living processes like data processing, video processing, etc. - -Motia has a built-in real-time streaming system that allows you to easily implement real-time streaming capabilities in your application. - -It's called Streams. - -## Stream Configuration - -Creating a Stream means defining a data schema that will be stored and served to the clients who are subscribing. - -### TypeScript Example - -```typescript -// steps/streams/chat-messages.stream.ts -import { StreamConfig } from 'motia' -import { z } from 'zod' - -export const chatMessageSchema = z.object({ - id: z.string(), - userId: z.string(), - message: z.string(), - timestamp: z.string() -}) - -export type ChatMessage = z.infer - -export const config: StreamConfig = { - /** - * This is the stream name, it's extremely important to - * be used on the client side. - */ - name: 'chatMessage', - - /** - * This is the schema of the data that will be stored in the stream. - * - * It helps Motia to create the types on the steps to enforce the - * streams objects are created correctly. - */ - schema: chatMessageSchema, - - /** - * Let's not worry about base config for now, all streams - * have this storage type default - */ - baseConfig: { storageType: 'default' }, -} -``` - -### Python Examples - -#### With Pydantic (Optional) - -```python -# steps/streams/chat_messages_stream.py -from pydantic import BaseModel - -class ChatMessage(BaseModel): - id: str - user_id: str - message: str - timestamp: str - -config = { - "name": "chatMessage", - "schema": ChatMessage.model_json_schema(), - "baseConfig": {"storageType": "default"} -} -``` - -#### Without Pydantic (Pure JSON Schema) - -```python -# steps/streams/chat_messages_stream.py - -config = { - "name": "chatMessage", - "schema": { - "type": "object", - "properties": { - "id": {"type": "string"}, - "user_id": {"type": "string"}, - "message": {"type": "string"}, - "timestamp": {"type": "string"} - }, - "required": ["id", "user_id", "message", "timestamp"] - }, - "baseConfig": {"storageType": "default"} -} -``` - -## Using streams - -Streams managers are automatically injected into the context of the steps. - -The interface of each stream is this - -```typescript -interface MotiaStream { - /** - * Retrieves a single item from the stream - * - * @param groupId - The group id of the stream - * @param id - The id of the item to get - * @returns The item or null if it doesn't exist - */ - get(groupId: string, id: string): Promise | null> - - /** - * Create or update a single item in the stream. - * - * If the item doesn't exist, it will be created. - * If the item exists, it will be updated. - * - * @param groupId - The group id of the stream - * @param id - The id of the item to set - * @param data - The data to set - * @returns The item - */ - set(groupId: string, id: string, data: TData): Promise> - - /** - * Deletes a single item from the stream - * - * @param groupId - The group id of the stream - * @param id - The id of the item to delete - * @returns The item or null if it doesn't exist - */ - delete(groupId: string, id: string): Promise | null> - - /** - * Retrieves a group of items from the stream based on the group id - * - * @param groupId - The group id of the stream - * @returns The items - */ - getGroup(groupId: string): Promise[]> - - /** - * This is used mostly for ephemeral events in streams. - * A chat message for example has a state, which is the message content, user id, etc. - * - * However, if you want to send an event to the subscribers like: - * - online status - * - reactions - * - typing indicators - * - etc. - * - * @param channel - The channel to send the event to - * @param event - The event to send - */ - send(channel: StateStreamEventChannel, event: StateStreamEvent): Promise -} -``` - -## Sending ephemeral events - -Streams hold state, which means when the client connects and subscribes to a GroupID and ItemID, -they will automatically sync with the state of the stream, however, there might be cases where -you want to send an ephemeral event to the subscribers, like: - -- online status -- reactions -- typing indicators -- etc. - -This is where the `send` method comes in. - -```typescript -/** - * The channel to send the event to - */ -type StateStreamEventChannel = { - /** - * The group id of the stream - */ - groupId: string - - /** - * The id of the item to send the event to - * - * Optional, when not provided, the event will be sent to the entire group. - * Subscribers to the group will receive the event. - */ - id?: string -} - -export type StateStreamEvent = { - /** - * The type of the event, use as the name of the event - * to be handled in the subscribers. - */ - type: string - - /** - * The data of the event, the data that will be sent to the subscribers. - */ - data: TData -} -``` - -## Using in handlers - -### TypeScript Example - -```typescript -import { ApiRouteConfig, Handlers } from 'motia' -import { z } from 'zod' -import { chatMessageSchema } from './streams/chat-messages.stream' - -export const config: ApiRouteConfig = { - type: 'api', - name: 'CreateChatMessage', - method: 'POST', - path: '/chat-messages', - bodySchema: z.object({ - channelId: z.string(), - message: z.string(), - }), - emits: [], - responseSchema: { - 201: chatMessageSchema - } -} - -export const handler = async (req, { streams }) => { - /** - * Say this is an API Step that a user sends a message to a channel. - * - * In your application logic you should have a channel ID defined somewhere - * so the client can send the message to the correct channel. - */ - const { channelId, message } = req.body - - /** - * Define the message ID however you want, but should be a unique identifier underneath the channel ID. - * - * This is used to identify the message in the stream. - */ - const messageId = crypto.randomUUID() - - /** - * In your application logic you should have a user ID defined somewhere. - * We recommend using middlewares to identify the user on the request. - */ - const userId = 'example-user-id' - - /** - * Creates a message in the stream - */ - const message = await streams.chatMessage.set(channelId, messageId, { - id: messageId, - userId: userId, - message: message, - timestamp: new Date().toISOString() - }) - - /** - * Returning the stream result directly to the client helps Workbench to - * render the stream object and update it in real-time in the UI. - */ - return { status: 201, body: message } -} -``` - -### Python Examples - -#### With Pydantic (Optional) - -```python -import uuid -from datetime import datetime -from pydantic import BaseModel - -class ChatMessageRequest(BaseModel): - channel_id: str - message: str - -class ChatMessageResponse(BaseModel): - id: str - user_id: str - message: str - timestamp: str - -config = { - "type": "api", - "name": "CreateChatMessage", - "method": "POST", - "path": "/chat-messages", - "bodySchema": ChatMessageRequest.model_json_schema(), - "emits": [], - "responseSchema": { - 201: ChatMessageResponse.model_json_schema() - } -} - -async def handler(req, context): - body = req.get("body", {}) - - # Optional: Validate with Pydantic - request_data = ChatMessageRequest(**body) - - channel_id = request_data.channel_id - message_text = request_data.message - - message_id = str(uuid.uuid4()) - user_id = "example-user-id" - - # Creates a message in the stream - chat_message = await context.streams.chatMessage.set(channel_id, message_id, { - "id": message_id, - "user_id": user_id, - "message": message_text, - "timestamp": datetime.now().isoformat() - }) - - return {"status": 201, "body": chat_message} -``` - -#### Without Pydantic (Pure JSON Schema) - -```python -import uuid -from datetime import datetime - -config = { - "type": "api", - "name": "CreateChatMessage", - "method": "POST", - "path": "/chat-messages", - "bodySchema": { - "type": "object", - "properties": { - "channel_id": {"type": "string"}, - "message": {"type": "string"} - }, - "required": ["channel_id", "message"] - }, - "emits": [], - "responseSchema": { - 201: { - "type": "object", - "properties": { - "id": {"type": "string"}, - "user_id": {"type": "string"}, - "message": {"type": "string"}, - "timestamp": {"type": "string"} - } - } - } -} - -async def handler(req, context): - body = req.get("body", {}) - channel_id = body.get("channel_id") - message_text = body.get("message") - - message_id = str(uuid.uuid4()) - user_id = "example-user-id" - - # Creates a message in the stream - chat_message = await context.streams.chatMessage.set(channel_id, message_id, { - "id": message_id, - "user_id": user_id, - "message": message_text, - "timestamp": datetime.now().isoformat() - }) - - return {"status": 201, "body": chat_message} -``` diff --git a/motia/.cursor/rules/motia/state-management.mdc b/motia/.cursor/rules/motia/state-management.mdc deleted file mode 100644 index ff517a4..0000000 --- a/motia/.cursor/rules/motia/state-management.mdc +++ /dev/null @@ -1,136 +0,0 @@ ---- -description: Managing state across Steps -globs: steps/**/*.step.ts,steps/**/*.step.js,steps/**/*_step.py -alwaysApply: false ---- - -# State Management - -State Management is a core concept in Motia. It's used to store data across Steps. -They can be stored across different workflows. - -If we want to trigger Event Steps, we can add data to the emit call, which can be used later in the Event Step execution. But this is limited and can't store too much data, -that's why we need to use the State Management to store data across Steps. - -## Use-cases - -**When State Management is recommended:** -- Pulling data from an external source, like an API, and storing it in the state, then triggering an Event Step to process the data. -- Storing data that needs to be used later in the workflow. -- Can be used for caching layer, like caching the result of an API call that usually can take a few seconds to complete and doesn't change very often. - -**When another solution can be better suited:** -- Storing persistent user data: it's preferred to use a database like Postgres or MongoDB to store user data. -- Storing file data like Base64 encoded images, PDFs, etc: it's preferred to use a storage solution like S3, etc. - -## StateManager Interface - -The StateManager interface is available in the context of all step handlers. The methods work identically across TypeScript/JavaScript and Python. - -```typescript -type InternalStateManager = { - /** - * Retrieves a single item from the state - * - * @param groupId - The group id of the state - * @param key - The key of the item to get - * @returns The item or null if it doesn't exist - */ - get(groupId: string, key: string): Promise - - /** - * Sets a single item in the state - * - * @param groupId - The group id of the state - * @param key - The key of the item to set - * @param value - The value of the item to set - * @returns The item - */ - set(groupId: string, key: string, value: T): Promise - - /** - * Deletes a single item from the state - * - * @param groupId - The group id of the state - * @param key - The key of the item to delete - * @returns The item or null if it doesn't exist - */ - delete(groupId: string, key: string): Promise - - /** - * Retrieves a group of items from the state - * - * @param groupId - The group id of the state - * @returns A list with all the items in the group - */ - getGroup(groupId: string): Promise - - /** - * Clears a group of items from the state - * - * @param groupId - The group id of the state - */ - clear(groupId: string): Promise -} -``` - -## Usage Examples - -### TypeScript/JavaScript Example - -```typescript -export const handler: Handlers['ProcessOrder'] = async (input, { state, logger }) => { - // Store an order - const order = { - id: input.orderId, - status: 'processing', - createdAt: new Date().toISOString() - }; - - await state.set('orders', input.orderId, order); - - // Retrieve an order - const savedOrder = await state.get('orders', input.orderId); - logger.info('Order retrieved', { savedOrder }); - - // Get all orders - const allOrders = await state.getGroup('orders'); - logger.info('Total orders', { count: allOrders.length }); - - // Update order status - order.status = 'completed'; - await state.set('orders', input.orderId, order); - - // Delete an order (if needed) - // await state.delete('orders', input.orderId); -}; -``` - -### Python Example - -```python -async def handler(input_data, context): - # Store an order - order = { - "id": input_data.get("order_id"), - "status": "processing", - "created_at": datetime.now().isoformat() - } - - await context.state.set("orders", input_data.get("order_id"), order) - - # Retrieve an order - saved_order = await context.state.get("orders", input_data.get("order_id")) - context.logger.info("Order retrieved", {"saved_order": saved_order}) - - # Get all orders - all_orders = await context.state.get_group("orders") - context.logger.info("Total orders", {"count": len(all_orders)}) - - # Update order status - order["status"] = "completed" - await context.state.set("orders", input_data.get("order_id"), order) - - # Delete an order (if needed) - # await context.state.delete("orders", input_data.get("order_id")) -``` diff --git a/motia/.cursor/rules/motia/ui-steps.mdc b/motia/.cursor/rules/motia/ui-steps.mdc deleted file mode 100644 index 46f8a97..0000000 --- a/motia/.cursor/rules/motia/ui-steps.mdc +++ /dev/null @@ -1,76 +0,0 @@ ---- -description: Overriding the UI of Steps in Motia -globs: steps/**/*.step.tsx,steps/**/*.step.jsx,steps/**/*_step.tsx,steps/**/*_step.jsx -alwaysApply: true ---- - -# UI Steps Guide for Motia - -UI Steps provide a powerful way to create custom, visually appealing representations of your workflow steps in the Workbench flow visualization tool. - -With UI Steps, you can enhance the user experience by designing intuitive, context-aware visual components that clearly communicate your flow's sequencing and events. - -## Overview - -To create a custom UI for a step, create a .tsx or .jsx file next to your step file with the same base name: - -``` -steps/ -└── myStep/ - ├── myStep.step.ts # Step definition - └── myStep.step.tsx # Visual override -``` - -## Basic Usage - -Let's override an EventNode but keeping the same look. Like the image below. We're going to add an image on the side and show the description. - -```typescript -// myStep.step.tsx - -import { EventNode, EventNodeProps } from 'motia/workbench' -import React from 'react' - -export const Node: React.FC = (props) => { - return ( - -
-
{props.data.description}
- -
-
- ) -} -``` - -## Components - -Motia Workbench provides out of the box components that you can use to create custom UI steps, which apply to different types of steps. - -### Available Components - -| Component | Props Type | Description | -|-----------|------------|-------------| -| EventNode | EventNodeProps | Base component for Event Steps, with built-in styling and connection points | -| ApiNode | ApiNodeProps | Component for API Steps, includes request/response visualization capabilities | -| CronNode | CronNodeProps | Base component for Cron Steps, displays timing information | -| NoopNode | NoopNodeProps | Base component for NoopNodes with a different color to comply workbench legend | - - -## Styling guidelines - -- Use Tailwind's utility classes only: Stick to Tailwind CSS utilities for consistent styling -- Avoid arbitrary values: Use predefined scales from the design system -- Keep components responsive: Ensure UI elements adapt well to different screen sizes -- Follow Motia's design system: Maintain consistency with Motia's established design patterns - -## Best practices - -- Use base components: Use EventNode and ApiNode when possible -- Keep it simple: Maintain simple and clear visualizations -- Optimize performance: Minimize state and computations -- Documentation: Document custom components and patterns -- Style sharing: Share common styles through utility classes \ No newline at end of file diff --git a/motia/.cursor/rules/motia/virtual-steps.mdc b/motia/.cursor/rules/motia/virtual-steps.mdc deleted file mode 100644 index 391a030..0000000 --- a/motia/.cursor/rules/motia/virtual-steps.mdc +++ /dev/null @@ -1,251 +0,0 @@ ---- -description: Connecting nodes virtually and creating a smooth flow in Workbench -globs: steps/**/*.step.ts,steps/**/*.step.js,steps/**/*_step.py -alwaysApply: false ---- - -# Virtual Steps Guide - -Virtual Steps are useful for creating a smooth flow in Workbench. - -They offer two ways to connect nodes virtually: -- NOOP Steps: Used mostly when we want to override the workflow to add buttons or show UI elements. -- Virtual Connections between steps: Used when we want to connect virtually two steps, with -or without NOOP Steps. - -## Creating NOOP Steps - -Steps need to be created in the `steps` folder, it can be in subfolders. - -- Steps in TS and JS should end with `.step.ts` and `.step.js` respectively. -- Steps in Python should end with `_step.py`. - -### Configuration - -#### TypeScript Example - -```typescript -import { NoopConfig } from 'motia' - -export const config: NoopConfig = { - /** - * Should always be noop - */ - type: 'noop', - - /** - * A unique name for this noop step, used internally and for linking handlers. - */ - name: 'manual-trigger', - - /** - * A description for this noop step, used for documentation and UI. - */ - description: 'Manual trigger point for workflow', - - /** - * An array of topics this step can emit events to. - */ - virtualEmits: ['workflow.start'], - - /** - * An array of topics this step can subscribe to. - */ - virtualSubscribes: ['manual.trigger'], - - /** - * An array of flow names this step belongs to. - */ - flows: ['my-workflow'] -} - -// NOOP steps don't need handlers - they're purely for Workbench workflow connections -``` - -#### Python Example - -```python -config = { - "type": "noop", - "name": "manual-trigger", - "description": "Manual trigger point for workflow", - "virtualEmits": ["workflow.start"], - "virtualSubscribes": ["manual.trigger"], - "flows": ["my-workflow"] -} - -# NOOP steps don't need handlers - they're purely for Workbench workflow connections -``` - -### Common Use Cases - -#### Workflow Starter - -This NOOP step will create a flow node in Workbench, then as a UI Step, we will override it -to show a button. - -**TypeScript:** -```typescript -export const config: NoopConfig = { - type: 'noop', - name: 'flow-starter', - description: 'Start point for the workflow', - virtualEmits: ['process.begin'], - virtualSubscribes: [], - flows: ['main-flow'] -} -``` - -**Python:** -```python -config = { - "type": "noop", - "name": "flow-starter", - "description": "Start point for the workflow", - "virtualEmits": ["process.begin"], - "virtualSubscribes": [], - "flows": ["main-flow"] -} -``` - -### Manual Approval Point - -This NOOP step will create a flow node in Workbench, it's important just to connect -a previous Step to the step where it will have a manual approval button. - -Example: - -```mermaid -graph LR - A[Submit Article] - C[Approve Article] - D[Reject Article] -``` - -Without this NOOP Step, the steps A->C and A->D would all appear disconnected in Workbench. - -**TypeScript:** -```typescript -export const config: NoopConfig = { - type: 'noop', - name: 'approval-gate', - description: 'Manual approval required', - virtualEmits: ['approved'], - virtualSubscribes: ['pending.approval'], - flows: ['approval-flow'] -} -``` - -**Python:** -```python -config = { - "type": "noop", - "name": "approval-gate", - "description": "Manual approval required", - "virtualEmits": ["approved"], - "virtualSubscribes": ["pending.approval"], - "flows": ["approval-flow"] -} -``` - -## How it works - -It uses the `virtualEmits` and `virtualSubscribes` to connect to the previous and next steps. - -In `Submit Article` Step, it must have a `virtualEmits: ['approved']` to connect to the `Manual Approval` Step. - -In `Approve Article` Step, it must have a `virtualSubscribes: ['pending.approval']` to connect to the `Submit Article` Step. - -It's also possible to connect two Steps without NOOP just by connecting them directly. -It's also possible to use labels in connections. - -**TypeScript Examples:** -```typescript -export const config: ApiRouteConfig = { - type: 'api', - name: 'CreateArticle', - path: '/articles', - method: 'POST', - description: 'Creates an article', - virtualEmits: [{ topic: 'approval.required', label: 'Requires approval' }], - emits: [], - flows: ['article'] -} - -export const config: ApiRouteConfig = { - type: 'api', - name: 'ApproveArticle', - path: '/articles/:id/approve', - method: 'POST', - description: 'Approves an article', - virtualSubscribes: ['approval.required'], - emits: [], - flows: ['article'] -} - -export const config: ApiRouteConfig = { - type: 'api', - name: 'RejectArticle', - path: '/articles/:id/reject', - method: 'POST', - description: 'Rejects an article', - virtualSubscribes: ['approval.required'], - emits: [], - flows: ['article'] -} -``` - -**Python Examples:** -```python -# create_article_step.py -config = { - "type": "api", - "name": "CreateArticle", - "path": "/articles", - "method": "POST", - "description": "Creates an article", - "virtualEmits": [{"topic": "approval.required", "label": "Requires approval"}], - "emits": [], - "flows": ["article"] -} - -# approve_article_step.py -config = { - "type": "api", - "name": "ApproveArticle", - "path": "/articles/:id/approve", - "method": "POST", - "description": "Approves an article", - "virtualSubscribes": ["approval.required"], - "emits": [], - "flows": ["article"] -} - -# reject_article_step.py -config = { - "type": "api", - "name": "RejectArticle", - "path": "/articles/:id/reject", - "method": "POST", - "description": "Rejects an article", - "virtualSubscribes": ["approval.required"], - "emits": [], - "flows": ["article"] -} -``` - -This will create connection to two API Steps. - - -```mermaid -graph LR - A[Create Article] --> B[Requires Approval] - B --> C[Approve Article] - B --> D[Reject Article] -``` - -## When to Use NOOP Steps -- Testing workflow connections -- Manual trigger points -- Workflow visualization -- Placeholder for future steps diff --git a/motia/.dockerignore b/motia/.dockerignore deleted file mode 100644 index 852b89a..0000000 --- a/motia/.dockerignore +++ /dev/null @@ -1,20 +0,0 @@ -node_modules -.env -.env.example -.git -.gitignore -.DS_Store -*.md -Dockerfile -.dockerignore -eslint.config.js -postman_collection_for_api_testing.json -README.md -.babelrc -tests -jest.config.js -tests/setup.js -*.test.js -*.spec.js -pnpm-lock.yaml -pnpm-store diff --git a/motia/.env.example b/motia/.env.example deleted file mode 100644 index c6a2089..0000000 --- a/motia/.env.example +++ /dev/null @@ -1,17 +0,0 @@ -# ZettaNote Motia Service Environment Variables -# Copy this file to .env and fill in your values - -# Service Configuration -NODE_ENV=development -MOTIA_PORT=3001 - -# Backend Integration -BACKEND_URL=http://localhost:4000 - -# Redis Configuration -REDIS_URL=redis://localhost:6379 - -# Cloudinary Configuration (for image cleanup) -CLOUDINARY_CLOUD_NAME=your_cloudinary_cloud_name -CLOUDINARY_API_KEY=your_cloudinary_api_key -CLOUDINARY_SECRET=your_cloudinary_secret \ No newline at end of file diff --git a/motia/.gitignore b/motia/.gitignore deleted file mode 100644 index 65fc01c..0000000 --- a/motia/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -node_modules -python_modules -.venv -venv -.motia -.mermaid -dist -*.pyc \ No newline at end of file diff --git a/motia/Dockerfile b/motia/Dockerfile deleted file mode 100644 index 0827323..0000000 --- a/motia/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -FROM node:20-alpine - -WORKDIR /app - -# Install pnpm -RUN npm install -g pnpm - -# Copy package files -COPY package.json pnpm-lock.yaml* ./ - -# Install dependencies (production only) -RUN pnpm install --prod && pnpm store prune - -# Copy application code -COPY . . - -# Environment variables -ENV NODE_ENV=production -ENV MOTIA_PORT=3001 - -EXPOSE 3001 - -# Health check -HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ - CMD node -e "require('http').get('http://localhost:3001/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" - -# Start the Motia service -CMD ["pnpm", "start"] diff --git a/motia/README.md b/motia/README.md deleted file mode 100644 index 6b114fa..0000000 --- a/motia/README.md +++ /dev/null @@ -1,97 +0,0 @@ -# ZettaNote Motia Service - -This is the Motia event-driven service for handling background tasks in ZettaNote. - -## Overview - -This service handles heavy background operations that would otherwise slow down the main backend: - -- **Image Cleanup**: Scheduled cleanup of unused images from Cloudinary -- **Task Reminders**: Email notifications for upcoming and overdue tasks -- **Async Page Saves**: Background processing of page content updates with image reference management -- **Async Image Uploads**: Background processing of image uploads to Cloudinary - -## Architecture - -The service uses Motia framework for event-driven workflows: - -- **API Steps**: HTTP endpoints that trigger background jobs -- **Event Steps**: Asynchronous processing of heavy operations -- **Cron Steps**: Scheduled tasks for recurring jobs -- **State Management**: Redis-based state storage for job tracking - -## Workflows - -### Image Management - -- `POST /cleanup/images` - Trigger manual image cleanup -- Scheduled cleanup every 6 hours (marked images + orphaned detection) -- Async image upload processing - -### Task Management - -- `POST /reminders/tasks` - Trigger manual reminder check -- Scheduled reminders every 5 minutes -- Email notifications for tasks due in 1 hour and overdue tasks - -### Page Management - -- `POST /pages/save` - Async page save with image reference updates -- Background processing of content changes and cache invalidation - -## Setup - -1. Install dependencies: - -```bash -pnpm install -``` - -2. Copy environment file: - -```bash -cp .env.example .env -``` - -3. Configure environment variables in `.env` - -4. Start the service: - -```bash -pnpm start -``` - -## Development - -```bash -# Development mode with hot reload -pnpm dev - -# Build for production -pnpm build -``` - -## Integration with Backend - -The Motia service communicates with the main backend via HTTP APIs. The backend should call Motia endpoints for heavy operations instead of processing them synchronously. - -### Example Integration - -Instead of processing image cleanup synchronously, the backend calls: - -```javascript -// Trigger async image cleanup -await axios.post('http://localhost:3001/cleanup/images', { - cleanupType: 'comprehensive', - batchSize: 50, -}); -``` - -## Monitoring - -Job status and results are stored in Redis state management. Use the following keys: - -- `cleanup-jobs:*` - Image cleanup job results -- `reminder-jobs:*` - Task reminder job results -- `page-save-jobs:*` - Page save job results -- `image-upload-jobs:*` - Image upload job results diff --git a/motia/motia-workbench.json b/motia/motia-workbench.json deleted file mode 100644 index 45c0900..0000000 --- a/motia/motia-workbench.json +++ /dev/null @@ -1,19 +0,0 @@ -[ - { - "id": "task-management", - "config": { - "steps/trigger-task-reminders.step.ts": { - "x": -293, - "y": 39 - }, - "steps/send-task-reminders.step.ts": { - "x": 421, - "y": 105 - }, - "steps/scheduled-task-reminders.step.ts": { - "x": -118, - "y": 206 - } - } - } -] diff --git a/motia/package.json b/motia/package.json deleted file mode 100644 index 41e54fb..0000000 --- a/motia/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "motia", - "description": "", - "scripts": { - "postinstall": "motia install", - "dev": "motia dev", - "start": "motia start --port 3001", - "generate-types": "motia generate-types", - "build": "motia build", - "clean": "rm -rf dist node_modules python_modules .motia .mermaid" - }, - "keywords": [ - "motia" - ], - "dependencies": { - "axios": "^1.12.2", - "motia": "^0.8.2-beta.139", - "zod": "^3.24.4" - }, - "devDependencies": { - "@types/node": "^24.9.1", - "@types/react": "^18.3.18", - "ts-node": "^10.9.2", - "typescript": "^5.7.3" - } -} diff --git a/motia/pnpm-lock.yaml b/motia/pnpm-lock.yaml deleted file mode 100644 index e98b6dc..0000000 --- a/motia/pnpm-lock.yaml +++ /dev/null @@ -1,7819 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - .: - dependencies: - axios: - specifier: ^1.12.2 - version: 1.12.2 - motia: - specifier: ^0.8.2-beta.139 - version: 0.8.2-beta.139(@types/node@24.9.1)(@types/react@18.3.26)(eslint@9.38.0(jiti@2.6.1))(jiti@2.6.1)(lightningcss@1.30.2)(monaco-editor@0.54.0)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@19.2.0)) - zod: - specifier: ^3.24.4 - version: 3.25.76 - devDependencies: - '@types/node': - specifier: ^24.9.1 - version: 24.9.1 - '@types/react': - specifier: ^18.3.18 - version: 18.3.26 - ts-node: - specifier: ^10.9.2 - version: 10.9.2(@types/node@24.9.1)(typescript@5.9.3) - typescript: - specifier: ^5.7.3 - version: 5.9.3 - -packages: - '@alloc/quick-lru@5.2.0': - resolution: - { - integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==, - } - engines: { node: '>=10' } - - '@amplitude/analytics-connector@1.6.4': - resolution: - { - integrity: sha512-SpIv0IQMNIq6SH3UqFGiaZyGSc7PBZwRdq7lvP0pBxW8i4Ny+8zwI0pV+VMfMHQwWY3wdIbWw5WQphNjpdq1/Q==, - } - - '@amplitude/analytics-core@2.30.0': - resolution: - { - integrity: sha512-oWz13sQmfCRa9prfYcURPVNHQQOf0/rDEK7PjBi0m0nKXs+QaHu/Tq2y4F6f4K66YDsT7zYYO4DpkS+QJM3/Sw==, - } - - '@amplitude/analytics-node@1.5.20': - resolution: - { - integrity: sha512-vjIhY5yE7TcI1XFdk2S0AC8ksrZpp+Drzu2F+npm8JZtosWBifn4LPceDXf5LbFFYPDhewc58XnK84zOo9DIkQ==, - } - - '@babel/code-frame@7.27.1': - resolution: - { - integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==, - } - engines: { node: '>=6.9.0' } - - '@babel/compat-data@7.28.5': - resolution: - { - integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==, - } - engines: { node: '>=6.9.0' } - - '@babel/core@7.28.5': - resolution: - { - integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==, - } - engines: { node: '>=6.9.0' } - - '@babel/generator@7.28.5': - resolution: - { - integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==, - } - engines: { node: '>=6.9.0' } - - '@babel/helper-compilation-targets@7.27.2': - resolution: - { - integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==, - } - engines: { node: '>=6.9.0' } - - '@babel/helper-globals@7.28.0': - resolution: - { - integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==, - } - engines: { node: '>=6.9.0' } - - '@babel/helper-module-imports@7.27.1': - resolution: - { - integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==, - } - engines: { node: '>=6.9.0' } - - '@babel/helper-module-transforms@7.28.3': - resolution: - { - integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==, - } - engines: { node: '>=6.9.0' } - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-plugin-utils@7.27.1': - resolution: - { - integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==, - } - engines: { node: '>=6.9.0' } - - '@babel/helper-string-parser@7.27.1': - resolution: - { - integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==, - } - engines: { node: '>=6.9.0' } - - '@babel/helper-validator-identifier@7.28.5': - resolution: - { - integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==, - } - engines: { node: '>=6.9.0' } - - '@babel/helper-validator-option@7.27.1': - resolution: - { - integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==, - } - engines: { node: '>=6.9.0' } - - '@babel/helpers@7.28.4': - resolution: - { - integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==, - } - engines: { node: '>=6.9.0' } - - '@babel/parser@7.28.5': - resolution: - { - integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==, - } - engines: { node: '>=6.0.0' } - hasBin: true - - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: - { - integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==, - } - engines: { node: '>=6.9.0' } - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: - { - integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==, - } - engines: { node: '>=6.9.0' } - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/runtime@7.28.4': - resolution: - { - integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==, - } - engines: { node: '>=6.9.0' } - - '@babel/template@7.27.2': - resolution: - { - integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==, - } - engines: { node: '>=6.9.0' } - - '@babel/traverse@7.28.5': - resolution: - { - integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==, - } - engines: { node: '>=6.9.0' } - - '@babel/types@7.28.5': - resolution: - { - integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==, - } - engines: { node: '>=6.9.0' } - - '@cspotcode/source-map-support@0.8.1': - resolution: - { - integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==, - } - engines: { node: '>=12' } - - '@esbuild/aix-ppc64@0.25.11': - resolution: - { - integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==, - } - engines: { node: '>=18' } - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.25.11': - resolution: - { - integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==, - } - engines: { node: '>=18' } - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.25.11': - resolution: - { - integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==, - } - engines: { node: '>=18' } - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.25.11': - resolution: - { - integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==, - } - engines: { node: '>=18' } - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.25.11': - resolution: - { - integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==, - } - engines: { node: '>=18' } - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.25.11': - resolution: - { - integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==, - } - engines: { node: '>=18' } - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.25.11': - resolution: - { - integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==, - } - engines: { node: '>=18' } - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.25.11': - resolution: - { - integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==, - } - engines: { node: '>=18' } - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.25.11': - resolution: - { - integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==, - } - engines: { node: '>=18' } - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.25.11': - resolution: - { - integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==, - } - engines: { node: '>=18' } - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.25.11': - resolution: - { - integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==, - } - engines: { node: '>=18' } - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.25.11': - resolution: - { - integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==, - } - engines: { node: '>=18' } - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.25.11': - resolution: - { - integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==, - } - engines: { node: '>=18' } - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.25.11': - resolution: - { - integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==, - } - engines: { node: '>=18' } - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.25.11': - resolution: - { - integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==, - } - engines: { node: '>=18' } - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.25.11': - resolution: - { - integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==, - } - engines: { node: '>=18' } - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.25.11': - resolution: - { - integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==, - } - engines: { node: '>=18' } - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.25.11': - resolution: - { - integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==, - } - engines: { node: '>=18' } - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.25.11': - resolution: - { - integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==, - } - engines: { node: '>=18' } - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.25.11': - resolution: - { - integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==, - } - engines: { node: '>=18' } - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.25.11': - resolution: - { - integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==, - } - engines: { node: '>=18' } - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.25.11': - resolution: - { - integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==, - } - engines: { node: '>=18' } - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.25.11': - resolution: - { - integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==, - } - engines: { node: '>=18' } - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.25.11': - resolution: - { - integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==, - } - engines: { node: '>=18' } - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.25.11': - resolution: - { - integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==, - } - engines: { node: '>=18' } - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.25.11': - resolution: - { - integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==, - } - engines: { node: '>=18' } - cpu: [x64] - os: [win32] - - '@eslint-community/eslint-utils@4.9.0': - resolution: - { - integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==, - } - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.2': - resolution: - { - integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==, - } - engines: { node: ^12.0.0 || ^14.0.0 || >=16.0.0 } - - '@eslint/config-array@0.21.1': - resolution: - { - integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - - '@eslint/config-helpers@0.4.1': - resolution: - { - integrity: sha512-csZAzkNhsgwb0I/UAV6/RGFTbiakPCf0ZrGmrIxQpYvGZ00PhTkSnyKNolphgIvmnJeGw6rcGVEXfTzUnFuEvw==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - - '@eslint/core@0.16.0': - resolution: - { - integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - - '@eslint/eslintrc@3.3.1': - resolution: - { - integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - - '@eslint/js@9.38.0': - resolution: - { - integrity: sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - - '@eslint/object-schema@2.1.7': - resolution: - { - integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - - '@eslint/plugin-kit@0.4.0': - resolution: - { - integrity: sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - - '@floating-ui/core@1.7.3': - resolution: - { - integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==, - } - - '@floating-ui/dom@1.7.4': - resolution: - { - integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==, - } - - '@floating-ui/react-dom@2.1.6': - resolution: - { - integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==, - } - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@floating-ui/utils@0.2.10': - resolution: - { - integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==, - } - - '@humanfs/core@0.19.1': - resolution: - { - integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==, - } - engines: { node: '>=18.18.0' } - - '@humanfs/node@0.16.7': - resolution: - { - integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==, - } - engines: { node: '>=18.18.0' } - - '@humanwhocodes/module-importer@1.0.1': - resolution: - { - integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==, - } - engines: { node: '>=12.22' } - - '@humanwhocodes/retry@0.4.3': - resolution: - { - integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==, - } - engines: { node: '>=18.18' } - - '@inquirer/external-editor@1.0.2': - resolution: - { - integrity: sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==, - } - engines: { node: '>=18' } - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@isaacs/balanced-match@4.0.1': - resolution: - { - integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==, - } - engines: { node: 20 || >=22 } - - '@isaacs/brace-expansion@5.0.0': - resolution: - { - integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==, - } - engines: { node: 20 || >=22 } - - '@isaacs/cliui@8.0.2': - resolution: - { - integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==, - } - engines: { node: '>=12' } - - '@jridgewell/gen-mapping@0.3.13': - resolution: - { - integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==, - } - - '@jridgewell/remapping@2.3.5': - resolution: - { - integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==, - } - - '@jridgewell/resolve-uri@3.1.2': - resolution: - { - integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, - } - engines: { node: '>=6.0.0' } - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: - { - integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==, - } - - '@jridgewell/trace-mapping@0.3.31': - resolution: - { - integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==, - } - - '@jridgewell/trace-mapping@0.3.9': - resolution: - { - integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==, - } - - '@monaco-editor/loader@1.6.1': - resolution: - { - integrity: sha512-w3tEnj9HYEC73wtjdpR089AqkUPskFRcdkxsiSFt3SoUc3OHpmu+leP94CXBm4mHfefmhsdfI0ZQu6qJ0wgtPg==, - } - - '@monaco-editor/react@4.7.0': - resolution: - { - integrity: sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==, - } - peerDependencies: - monaco-editor: '>= 0.25.0 < 1' - 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 - - '@motiadev/core@0.8.2-beta.139': - resolution: - { - integrity: sha512-ueIGi5PsYU7TmeG2GrIXTUTdS6D9pFUzgft1vOx0rkl9YRIKevsm5IDHapjg8ZchbSLhKJyYuCeROH8AOsIXow==, - } - - '@motiadev/plugin-endpoint@0.8.2-beta.139': - resolution: - { - integrity: sha512-KKmo9hptNXhgQLbDhcyVKGuMETfowQ4Dp4utBQCfUHr/mLbZdO14lNqPpo5dEgc4VaXq0Ldc8YbgDhDorkAJ1w==, - } - - '@motiadev/stream-client-browser@0.8.2-beta.139': - resolution: - { - integrity: sha512-FF4GsAWRd6QKcWAvALL3IQ5RDreTR1uqMCTJj81qUci+YTp8joiWo7a8spMdttOgRWUu3xI1QrKPO2PjkeAzvg==, - } - - '@motiadev/stream-client-node@0.8.2-beta.139': - resolution: - { - integrity: sha512-UBZOtv6jrXGcm1nH8JgTBB2wgfgh+hmVSm5YZqrDgwxTDMr7GxXFHa7j1AnGy7B+fc+xSZwRPmzewIxPYc59Tg==, - } - - '@motiadev/stream-client-react@0.8.2-beta.139': - resolution: - { - integrity: sha512-FaTMgLYB3LkVvXhcBGGDENJCI+1ezSfH4YSvUtkId9lqYs09Kwxk69w8F/SLjTNQvf/4csarr0LD4IGdveJ2dQ==, - } - peerDependencies: - react: ^19.1.0 - - '@motiadev/stream-client@0.8.2-beta.139': - resolution: - { - integrity: sha512-NVe0r4Jl+b9QD92FK8B4bpkvvjFauhTdLtcQyv/5g2CZ7azC2IG3Fz0vw6+qe28+37L7IrpTxRWnSTkULlyazA==, - } - - '@motiadev/ui@0.8.2-beta.139': - resolution: - { - integrity: sha512-Q5yFfehQhIerhoKwQrk8elyGSB9mBrTXgEhnOeRLE/p+qzeKPjaqRxF0O1L98AT0H++aFRwwdx1io9doIhxJWw==, - } - peerDependencies: - react: ^19.1.0 - react-dom: ^19.1.0 - - '@motiadev/workbench@0.8.2-beta.139': - resolution: - { - integrity: sha512-8Ivo2aOVTPGQzx0bTg/3Qhpsrv+L4KK7B3cQmZPmkdoG88pH5ojLBql3sMZCmdTOMYFhD78puw3BMMuSb2Ev4g==, - } - - '@nodelib/fs.scandir@2.1.5': - resolution: - { - integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==, - } - engines: { node: '>= 8' } - - '@nodelib/fs.stat@2.0.5': - resolution: - { - integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==, - } - engines: { node: '>= 8' } - - '@nodelib/fs.walk@1.2.8': - resolution: - { - integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==, - } - engines: { node: '>= 8' } - - '@pkgjs/parseargs@0.11.0': - resolution: - { - integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==, - } - engines: { node: '>=14' } - - '@radix-ui/number@1.1.1': - resolution: - { - integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==, - } - - '@radix-ui/primitive@1.1.3': - resolution: - { - integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==, - } - - '@radix-ui/react-arrow@1.1.7': - resolution: - { - integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-checkbox@1.3.3': - resolution: - { - integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-collapsible@1.1.12': - resolution: - { - integrity: sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-collection@1.1.7': - resolution: - { - integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-compose-refs@1.1.2': - resolution: - { - integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==, - } - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-context@1.1.2': - resolution: - { - integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==, - } - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dialog@1.1.15': - resolution: - { - integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-direction@1.1.1': - resolution: - { - integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==, - } - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dismissable-layer@1.1.11': - resolution: - { - integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-dropdown-menu@2.1.16': - resolution: - { - integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-focus-guards@1.1.3': - resolution: - { - integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==, - } - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-focus-scope@1.1.7': - resolution: - { - integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-id@1.1.1': - resolution: - { - integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==, - } - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-label@2.1.7': - resolution: - { - integrity: sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-menu@2.1.16': - resolution: - { - integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-navigation-menu@1.2.14': - resolution: - { - integrity: sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-popper@1.2.8': - resolution: - { - integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-portal@1.1.9': - resolution: - { - integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-presence@1.1.5': - resolution: - { - integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-primitive@2.1.3': - resolution: - { - integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-roving-focus@1.1.11': - resolution: - { - integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-scroll-area@1.2.10': - resolution: - { - integrity: sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-select@2.2.6': - resolution: - { - integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-separator@1.1.7': - resolution: - { - integrity: sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-slot@1.2.3': - resolution: - { - integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==, - } - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-switch@1.2.6': - resolution: - { - integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-tabs@1.1.13': - resolution: - { - integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-tooltip@1.2.8': - resolution: - { - integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-use-callback-ref@1.1.1': - resolution: - { - integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==, - } - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-controllable-state@1.2.2': - resolution: - { - integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==, - } - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-effect-event@0.0.2': - resolution: - { - integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==, - } - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-escape-keydown@1.1.1': - resolution: - { - integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==, - } - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-layout-effect@1.1.1': - resolution: - { - integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==, - } - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-previous@1.1.1': - resolution: - { - integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==, - } - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-rect@1.1.1': - resolution: - { - integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==, - } - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-size@1.1.1': - resolution: - { - integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==, - } - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-visually-hidden@1.2.3': - resolution: - { - integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==, - } - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/rect@1.1.1': - resolution: - { - integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==, - } - - '@rolldown/pluginutils@1.0.0-beta.27': - resolution: - { - integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==, - } - - '@rollup/rollup-android-arm-eabi@4.52.5': - resolution: - { - integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==, - } - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.52.5': - resolution: - { - integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==, - } - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.52.5': - resolution: - { - integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==, - } - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.52.5': - resolution: - { - integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==, - } - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.52.5': - resolution: - { - integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==, - } - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.52.5': - resolution: - { - integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==, - } - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.52.5': - resolution: - { - integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==, - } - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.52.5': - resolution: - { - integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==, - } - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.52.5': - resolution: - { - integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==, - } - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.52.5': - resolution: - { - integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==, - } - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-loong64-gnu@4.52.5': - resolution: - { - integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==, - } - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-ppc64-gnu@4.52.5': - resolution: - { - integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==, - } - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.52.5': - resolution: - { - integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==, - } - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.52.5': - resolution: - { - integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==, - } - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.52.5': - resolution: - { - integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==, - } - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.52.5': - resolution: - { - integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==, - } - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.52.5': - resolution: - { - integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==, - } - cpu: [x64] - os: [linux] - - '@rollup/rollup-openharmony-arm64@4.52.5': - resolution: - { - integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==, - } - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.52.5': - resolution: - { - integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==, - } - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.52.5': - resolution: - { - integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==, - } - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.52.5': - resolution: - { - integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==, - } - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.52.5': - resolution: - { - integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==, - } - cpu: [x64] - os: [win32] - - '@tailwindcss/node@4.1.16': - resolution: - { - integrity: sha512-BX5iaSsloNuvKNHRN3k2RcCuTEgASTo77mofW0vmeHkfrDWaoFAFvNHpEgtu0eqyypcyiBkDWzSMxJhp3AUVcw==, - } - - '@tailwindcss/oxide-android-arm64@4.1.16': - resolution: - { - integrity: sha512-8+ctzkjHgwDJ5caq9IqRSgsP70xhdhJvm+oueS/yhD5ixLhqTw9fSL1OurzMUhBwE5zK26FXLCz2f/RtkISqHA==, - } - engines: { node: '>= 10' } - cpu: [arm64] - os: [android] - - '@tailwindcss/oxide-darwin-arm64@4.1.16': - resolution: - { - integrity: sha512-C3oZy5042v2FOALBZtY0JTDnGNdS6w7DxL/odvSny17ORUnaRKhyTse8xYi3yKGyfnTUOdavRCdmc8QqJYwFKA==, - } - engines: { node: '>= 10' } - cpu: [arm64] - os: [darwin] - - '@tailwindcss/oxide-darwin-x64@4.1.16': - resolution: - { - integrity: sha512-vjrl/1Ub9+JwU6BP0emgipGjowzYZMjbWCDqwA2Z4vCa+HBSpP4v6U2ddejcHsolsYxwL5r4bPNoamlV0xDdLg==, - } - engines: { node: '>= 10' } - cpu: [x64] - os: [darwin] - - '@tailwindcss/oxide-freebsd-x64@4.1.16': - resolution: - { - integrity: sha512-TSMpPYpQLm+aR1wW5rKuUuEruc/oOX3C7H0BTnPDn7W/eMw8W+MRMpiypKMkXZfwH8wqPIRKppuZoedTtNj2tg==, - } - engines: { node: '>= 10' } - cpu: [x64] - os: [freebsd] - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.16': - resolution: - { - integrity: sha512-p0GGfRg/w0sdsFKBjMYvvKIiKy/LNWLWgV/plR4lUgrsxFAoQBFrXkZ4C0w8IOXfslB9vHK/JGASWD2IefIpvw==, - } - engines: { node: '>= 10' } - cpu: [arm] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-gnu@4.1.16': - resolution: - { - integrity: sha512-DoixyMmTNO19rwRPdqviTrG1rYzpxgyYJl8RgQvdAQUzxC1ToLRqtNJpU/ATURSKgIg6uerPw2feW0aS8SNr/w==, - } - engines: { node: '>= 10' } - cpu: [arm64] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-musl@4.1.16': - resolution: - { - integrity: sha512-H81UXMa9hJhWhaAUca6bU2wm5RRFpuHImrwXBUvPbYb+3jo32I9VIwpOX6hms0fPmA6f2pGVlybO6qU8pF4fzQ==, - } - engines: { node: '>= 10' } - cpu: [arm64] - os: [linux] - - '@tailwindcss/oxide-linux-x64-gnu@4.1.16': - resolution: - { - integrity: sha512-ZGHQxDtFC2/ruo7t99Qo2TTIvOERULPl5l0K1g0oK6b5PGqjYMga+FcY1wIUnrUxY56h28FxybtDEla+ICOyew==, - } - engines: { node: '>= 10' } - cpu: [x64] - os: [linux] - - '@tailwindcss/oxide-linux-x64-musl@4.1.16': - resolution: - { - integrity: sha512-Oi1tAaa0rcKf1Og9MzKeINZzMLPbhxvm7rno5/zuP1WYmpiG0bEHq4AcRUiG2165/WUzvxkW4XDYCscZWbTLZw==, - } - engines: { node: '>= 10' } - cpu: [x64] - os: [linux] - - '@tailwindcss/oxide-wasm32-wasi@4.1.16': - resolution: - { - integrity: sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q==, - } - engines: { node: '>=14.0.0' } - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' - - '@emnapi/wasi-threads' - - tslib - - '@tailwindcss/oxide-win32-arm64-msvc@4.1.16': - resolution: - { - integrity: sha512-zX+Q8sSkGj6HKRTMJXuPvOcP8XfYON24zJBRPlszcH1Np7xuHXhWn8qfFjIujVzvH3BHU+16jBXwgpl20i+v9A==, - } - engines: { node: '>= 10' } - cpu: [arm64] - os: [win32] - - '@tailwindcss/oxide-win32-x64-msvc@4.1.16': - resolution: - { - integrity: sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg==, - } - engines: { node: '>= 10' } - cpu: [x64] - os: [win32] - - '@tailwindcss/oxide@4.1.16': - resolution: - { - integrity: sha512-2OSv52FRuhdlgyOQqgtQHuCgXnS8nFSYRp2tJ+4WZXKgTxqPy7SMSls8c3mPT5pkZ17SBToGM5LHEJBO7miEdg==, - } - engines: { node: '>= 10' } - - '@tailwindcss/postcss@4.1.16': - resolution: - { - integrity: sha512-Qn3SFGPXYQMKR/UtqS+dqvPrzEeBZHrFA92maT4zijCVggdsXnDBMsPFJo1eArX3J+O+Gi+8pV4PkqjLCNBk3A==, - } - - '@tsconfig/node10@1.0.11': - resolution: - { - integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==, - } - - '@tsconfig/node12@1.0.11': - resolution: - { - integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==, - } - - '@tsconfig/node14@1.0.3': - resolution: - { - integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==, - } - - '@tsconfig/node16@1.0.4': - resolution: - { - integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==, - } - - '@types/babel__core@7.20.5': - resolution: - { - integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==, - } - - '@types/babel__generator@7.27.0': - resolution: - { - integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==, - } - - '@types/babel__template@7.4.4': - resolution: - { - integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==, - } - - '@types/babel__traverse@7.28.0': - resolution: - { - integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==, - } - - '@types/d3-color@3.1.3': - resolution: - { - integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==, - } - - '@types/d3-drag@3.0.7': - resolution: - { - integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==, - } - - '@types/d3-interpolate@3.0.4': - resolution: - { - integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==, - } - - '@types/d3-selection@3.0.11': - resolution: - { - integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==, - } - - '@types/d3-transition@3.0.9': - resolution: - { - integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==, - } - - '@types/d3-zoom@3.0.8': - resolution: - { - integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==, - } - - '@types/estree@1.0.8': - resolution: - { - integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==, - } - - '@types/hast@2.3.10': - resolution: - { - integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==, - } - - '@types/json-schema@7.0.15': - resolution: - { - integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==, - } - - '@types/luxon@3.7.1': - resolution: - { - integrity: sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg==, - } - - '@types/node@24.9.1': - resolution: - { - integrity: sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==, - } - - '@types/prop-types@15.7.15': - resolution: - { - integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==, - } - - '@types/react@18.3.26': - resolution: - { - integrity: sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==, - } - - '@types/unist@2.0.11': - resolution: - { - integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==, - } - - '@typescript-eslint/eslint-plugin@8.46.2': - resolution: - { - integrity: sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - peerDependencies: - '@typescript-eslint/parser': ^8.46.2 - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/parser@8.46.2': - resolution: - { - integrity: sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/project-service@8.46.2': - resolution: - { - integrity: sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/scope-manager@8.46.2': - resolution: - { - integrity: sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - - '@typescript-eslint/tsconfig-utils@8.46.2': - resolution: - { - integrity: sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/type-utils@8.46.2': - resolution: - { - integrity: sha512-HbPM4LbaAAt/DjxXaG9yiS9brOOz6fabal4uvUmaUYe6l3K1phQDMQKBRUrr06BQkxkvIZVVHttqiybM9nJsLA==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/types@8.46.2': - resolution: - { - integrity: sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - - '@typescript-eslint/typescript-estree@8.46.2': - resolution: - { - integrity: sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/utils@8.46.2': - resolution: - { - integrity: sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/visitor-keys@8.46.2': - resolution: - { - integrity: sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - - '@vitejs/plugin-react@4.7.0': - resolution: - { - integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==, - } - engines: { node: ^14.18.0 || >=16.0.0 } - peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - - '@xyflow/react@12.9.0': - resolution: - { - integrity: sha512-bt37E8Wf2HQ7hHQaMSnOw4UEWQqWlNwzfgF9tjix5Fu9Pn/ph3wbexSS/wbWnTkv0vhgMVyphQLfFWIuCe59hQ==, - } - peerDependencies: - react: '>=17' - react-dom: '>=17' - - '@xyflow/system@0.0.71': - resolution: - { - integrity: sha512-O2xIK84Uv1hH8qzeY94SKsj0R1n2jXHLsX6RZnM4x1Uc4oWiVbXDFucnkbFwhnQm3IIdAxkbgd2rEDp5oTRhhQ==, - } - - abort-controller@3.0.0: - resolution: - { - integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==, - } - engines: { node: '>=6.5' } - - accepts@1.3.8: - resolution: - { - integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==, - } - engines: { node: '>= 0.6' } - - acorn-jsx@5.3.2: - resolution: - { - integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, - } - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn-walk@8.3.4: - resolution: - { - integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==, - } - engines: { node: '>=0.4.0' } - - acorn@8.15.0: - resolution: - { - integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==, - } - engines: { node: '>=0.4.0' } - hasBin: true - - ajv@6.12.6: - resolution: - { - integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==, - } - - ajv@8.17.1: - resolution: - { - integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==, - } - - ansi-escapes@4.3.2: - resolution: - { - integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==, - } - engines: { node: '>=8' } - - ansi-regex@5.0.1: - resolution: - { - integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, - } - engines: { node: '>=8' } - - ansi-regex@6.2.2: - resolution: - { - integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==, - } - engines: { node: '>=12' } - - ansi-styles@4.3.0: - resolution: - { - integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, - } - engines: { node: '>=8' } - - ansi-styles@6.2.3: - resolution: - { - integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==, - } - engines: { node: '>=12' } - - antlr4ts@0.5.0-alpha.4: - resolution: - { - integrity: sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==, - } - - archiver-utils@5.0.2: - resolution: - { - integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==, - } - engines: { node: '>= 14' } - - archiver@7.0.1: - resolution: - { - integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==, - } - engines: { node: '>= 14' } - - arg@4.1.3: - resolution: - { - integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==, - } - - argparse@2.0.1: - resolution: - { - integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, - } - - aria-hidden@1.2.6: - resolution: - { - integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==, - } - engines: { node: '>=10' } - - array-flatten@1.1.1: - resolution: - { - integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==, - } - - astral-regex@2.0.0: - resolution: - { - integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==, - } - engines: { node: '>=8' } - - async@3.2.6: - resolution: - { - integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==, - } - - asynckit@0.4.0: - resolution: - { - integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==, - } - - autoprefixer@10.4.21: - resolution: - { - integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==, - } - engines: { node: ^10 || ^12 || >=14 } - hasBin: true - peerDependencies: - postcss: ^8.1.0 - - axios@1.12.2: - resolution: - { - integrity: sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==, - } - - b4a@1.7.3: - resolution: - { - integrity: sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==, - } - peerDependencies: - react-native-b4a: '*' - peerDependenciesMeta: - react-native-b4a: - optional: true - - balanced-match@1.0.2: - resolution: - { - integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, - } - - bare-events@2.8.1: - resolution: - { - integrity: sha512-oxSAxTS1hRfnyit2CL5QpAOS5ixfBjj6ex3yTNvXyY/kE719jQ/IjuESJBK2w5v4wwQRAHGseVJXx9QBYOtFGQ==, - } - peerDependencies: - bare-abort-controller: '*' - peerDependenciesMeta: - bare-abort-controller: - optional: true - - base64-js@1.5.1: - resolution: - { - integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==, - } - - baseline-browser-mapping@2.8.20: - resolution: - { - integrity: sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ==, - } - hasBin: true - - bl@4.1.0: - resolution: - { - integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==, - } - - body-parser@1.20.3: - resolution: - { - integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==, - } - engines: { node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16 } - - brace-expansion@1.1.12: - resolution: - { - integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==, - } - - brace-expansion@2.0.2: - resolution: - { - integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==, - } - - braces@3.0.3: - resolution: - { - integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==, - } - engines: { node: '>=8' } - - browserslist@4.27.0: - resolution: - { - integrity: sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==, - } - engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } - hasBin: true - - buffer-crc32@1.0.0: - resolution: - { - integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==, - } - engines: { node: '>=8.0.0' } - - buffer@5.7.1: - resolution: - { - integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==, - } - - buffer@6.0.3: - resolution: - { - integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==, - } - - bytes@3.1.2: - resolution: - { - integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==, - } - engines: { node: '>= 0.8' } - - call-bind-apply-helpers@1.0.2: - resolution: - { - integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==, - } - engines: { node: '>= 0.4' } - - call-bound@1.0.4: - resolution: - { - integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==, - } - engines: { node: '>= 0.4' } - - callsites@3.1.0: - resolution: - { - integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, - } - engines: { node: '>=6' } - - caniuse-lite@1.0.30001751: - resolution: - { - integrity: sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==, - } - - chalk@4.1.2: - resolution: - { - integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, - } - engines: { node: '>=10' } - - character-entities-legacy@1.1.4: - resolution: - { - integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==, - } - - character-entities@1.2.4: - resolution: - { - integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==, - } - - character-reference-invalid@1.1.4: - resolution: - { - integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==, - } - - chardet@2.1.0: - resolution: - { - integrity: sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==, - } - - chokidar@4.0.3: - resolution: - { - integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==, - } - engines: { node: '>= 14.16.0' } - - class-variance-authority@0.7.1: - resolution: - { - integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==, - } - - classcat@5.0.5: - resolution: - { - integrity: sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==, - } - - cli-cursor@3.1.0: - resolution: - { - integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==, - } - engines: { node: '>=8' } - - cli-spinners@2.9.2: - resolution: - { - integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==, - } - engines: { node: '>=6' } - - cli-width@3.0.0: - resolution: - { - integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==, - } - engines: { node: '>= 10' } - - clone@1.0.4: - resolution: - { - integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==, - } - engines: { node: '>=0.8' } - - clsx@2.1.1: - resolution: - { - integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==, - } - engines: { node: '>=6' } - - color-convert@2.0.1: - resolution: - { - integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, - } - engines: { node: '>=7.0.0' } - - color-name@1.1.4: - resolution: - { - integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, - } - - colors@1.4.0: - resolution: - { - integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==, - } - engines: { node: '>=0.1.90' } - - combined-stream@1.0.8: - resolution: - { - integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, - } - engines: { node: '>= 0.8' } - - comma-separated-tokens@1.0.8: - resolution: - { - integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==, - } - - commander@13.1.0: - resolution: - { - integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==, - } - engines: { node: '>=18' } - - compress-commons@6.0.2: - resolution: - { - integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==, - } - engines: { node: '>= 14' } - - concat-map@0.0.1: - resolution: - { - integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, - } - - content-disposition@0.5.4: - resolution: - { - integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==, - } - engines: { node: '>= 0.6' } - - content-type@1.0.5: - resolution: - { - integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==, - } - engines: { node: '>= 0.6' } - - convert-source-map@2.0.0: - resolution: - { - integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==, - } - - cookie-signature@1.0.6: - resolution: - { - integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==, - } - - cookie@0.7.1: - resolution: - { - integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==, - } - engines: { node: '>= 0.6' } - - copy-to-clipboard@3.3.3: - resolution: - { - integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==, - } - - core-util-is@1.0.3: - resolution: - { - integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==, - } - - crc-32@1.2.2: - resolution: - { - integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==, - } - engines: { node: '>=0.8' } - hasBin: true - - crc32-stream@6.0.0: - resolution: - { - integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==, - } - engines: { node: '>= 14' } - - create-require@1.1.1: - resolution: - { - integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==, - } - - cron@4.3.3: - resolution: - { - integrity: sha512-B/CJj5yL3sjtlun6RtYHvoSB26EmQ2NUmhq9ZiJSyKIM4K/fqfh9aelDFlIayD2YMeFZqWLi9hHV+c+pq2Djkw==, - } - engines: { node: '>=18.x' } - - cross-spawn@7.0.6: - resolution: - { - integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==, - } - engines: { node: '>= 8' } - - csstype@3.1.3: - resolution: - { - integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==, - } - - d3-color@3.1.0: - resolution: - { - integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==, - } - engines: { node: '>=12' } - - d3-dispatch@3.0.1: - resolution: - { - integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==, - } - engines: { node: '>=12' } - - d3-drag@3.0.0: - resolution: - { - integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==, - } - engines: { node: '>=12' } - - d3-ease@3.0.1: - resolution: - { - integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==, - } - engines: { node: '>=12' } - - d3-interpolate@3.0.1: - resolution: - { - integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==, - } - engines: { node: '>=12' } - - d3-selection@3.0.0: - resolution: - { - integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==, - } - engines: { node: '>=12' } - - d3-timer@3.0.1: - resolution: - { - integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==, - } - engines: { node: '>=12' } - - d3-transition@3.0.1: - resolution: - { - integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==, - } - engines: { node: '>=12' } - peerDependencies: - d3-selection: 2 - 3 - - d3-zoom@3.0.0: - resolution: - { - integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==, - } - engines: { node: '>=12' } - - dagre@0.8.5: - resolution: - { - integrity: sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==, - } - - date-fns@4.1.0: - resolution: - { - integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==, - } - - debug@2.6.9: - resolution: - { - integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==, - } - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@4.4.3: - resolution: - { - integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==, - } - engines: { node: '>=6.0' } - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - deep-is@0.1.4: - resolution: - { - integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, - } - - defaults@1.0.4: - resolution: - { - integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==, - } - - delayed-stream@1.0.0: - resolution: - { - integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==, - } - engines: { node: '>=0.4.0' } - - depd@2.0.0: - resolution: - { - integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==, - } - engines: { node: '>= 0.8' } - - destroy@1.2.0: - resolution: - { - integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==, - } - engines: { node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16 } - - detect-libc@2.1.2: - resolution: - { - integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==, - } - engines: { node: '>=8' } - - detect-node-es@1.1.0: - resolution: - { - integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==, - } - - diff@4.0.2: - resolution: - { - integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==, - } - engines: { node: '>=0.3.1' } - - dompurify@3.1.7: - resolution: - { - integrity: sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==, - } - - dotenv@16.6.1: - resolution: - { - integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==, - } - engines: { node: '>=12' } - - dunder-proto@1.0.1: - resolution: - { - integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==, - } - engines: { node: '>= 0.4' } - - eastasianwidth@0.2.0: - resolution: - { - integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==, - } - - ee-first@1.1.1: - resolution: - { - integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==, - } - - electron-to-chromium@1.5.240: - resolution: - { - integrity: sha512-OBwbZjWgrCOH+g6uJsA2/7Twpas2OlepS9uvByJjR2datRDuKGYeD+nP8lBBks2qnB7bGJNHDUx7c/YLaT3QMQ==, - } - - emoji-regex@8.0.0: - resolution: - { - integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, - } - - emoji-regex@9.2.2: - resolution: - { - integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, - } - - encodeurl@1.0.2: - resolution: - { - integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==, - } - engines: { node: '>= 0.8' } - - encodeurl@2.0.0: - resolution: - { - integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==, - } - engines: { node: '>= 0.8' } - - enhanced-resolve@5.18.3: - resolution: - { - integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==, - } - engines: { node: '>=10.13.0' } - - es-define-property@1.0.1: - resolution: - { - integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==, - } - engines: { node: '>= 0.4' } - - es-errors@1.3.0: - resolution: - { - integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==, - } - engines: { node: '>= 0.4' } - - es-object-atoms@1.1.1: - resolution: - { - integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==, - } - engines: { node: '>= 0.4' } - - es-set-tostringtag@2.1.0: - resolution: - { - integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==, - } - engines: { node: '>= 0.4' } - - esbuild@0.25.11: - resolution: - { - integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==, - } - engines: { node: '>=18' } - hasBin: true - - escalade@3.2.0: - resolution: - { - integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==, - } - engines: { node: '>=6' } - - escape-html@1.0.3: - resolution: - { - integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==, - } - - escape-string-regexp@1.0.5: - resolution: - { - integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==, - } - engines: { node: '>=0.8.0' } - - escape-string-regexp@4.0.0: - resolution: - { - integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==, - } - engines: { node: '>=10' } - - eslint-scope@8.4.0: - resolution: - { - integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - - eslint-visitor-keys@3.4.3: - resolution: - { - integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==, - } - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } - - eslint-visitor-keys@4.2.1: - resolution: - { - integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - - eslint@9.38.0: - resolution: - { - integrity: sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - - espree@10.4.0: - resolution: - { - integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - - esquery@1.6.0: - resolution: - { - integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==, - } - engines: { node: '>=0.10' } - - esrecurse@4.3.0: - resolution: - { - integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==, - } - engines: { node: '>=4.0' } - - estraverse@5.3.0: - resolution: - { - integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==, - } - engines: { node: '>=4.0' } - - esutils@2.0.3: - resolution: - { - integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==, - } - engines: { node: '>=0.10.0' } - - etag@1.8.1: - resolution: - { - integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==, - } - engines: { node: '>= 0.6' } - - event-target-shim@5.0.1: - resolution: - { - integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==, - } - engines: { node: '>=6' } - - events-universal@1.0.1: - resolution: - { - integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==, - } - - events@3.3.0: - resolution: - { - integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==, - } - engines: { node: '>=0.8.x' } - - express@4.21.2: - resolution: - { - integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==, - } - engines: { node: '>= 0.10.0' } - - fast-deep-equal@3.1.3: - resolution: - { - integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, - } - - fast-fifo@1.3.2: - resolution: - { - integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==, - } - - fast-glob@3.3.3: - resolution: - { - integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==, - } - engines: { node: '>=8.6.0' } - - fast-json-stable-stringify@2.1.0: - resolution: - { - integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==, - } - - fast-levenshtein@2.0.6: - resolution: - { - integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, - } - - fast-uri@3.1.0: - resolution: - { - integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==, - } - - fastq@1.19.1: - resolution: - { - integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==, - } - - fault@1.0.4: - resolution: - { - integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==, - } - - fdir@6.5.0: - resolution: - { - integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==, - } - engines: { node: '>=12.0.0' } - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - figures@3.2.0: - resolution: - { - integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==, - } - engines: { node: '>=8' } - - file-entry-cache@8.0.0: - resolution: - { - integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==, - } - engines: { node: '>=16.0.0' } - - fill-range@7.1.1: - resolution: - { - integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==, - } - engines: { node: '>=8' } - - finalhandler@1.3.1: - resolution: - { - integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==, - } - engines: { node: '>= 0.8' } - - find-up@5.0.0: - resolution: - { - integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==, - } - engines: { node: '>=10' } - - flat-cache@4.0.1: - resolution: - { - integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==, - } - engines: { node: '>=16' } - - flatted@3.3.3: - resolution: - { - integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==, - } - - follow-redirects@1.15.11: - resolution: - { - integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==, - } - engines: { node: '>=4.0' } - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - - foreground-child@3.3.1: - resolution: - { - integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==, - } - engines: { node: '>=14' } - - form-data@4.0.4: - resolution: - { - integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==, - } - engines: { node: '>= 6' } - - format@0.2.2: - resolution: - { - integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==, - } - engines: { node: '>=0.4.x' } - - forwarded@0.2.0: - resolution: - { - integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==, - } - engines: { node: '>= 0.6' } - - fraction.js@4.3.7: - resolution: - { - integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==, - } - - fresh@0.5.2: - resolution: - { - integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==, - } - engines: { node: '>= 0.6' } - - fsevents@2.3.3: - resolution: - { - integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, - } - engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } - os: [darwin] - - function-bind@1.1.2: - resolution: - { - integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==, - } - - gensync@1.0.0-beta.2: - resolution: - { - integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==, - } - engines: { node: '>=6.9.0' } - - get-intrinsic@1.3.0: - resolution: - { - integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==, - } - engines: { node: '>= 0.4' } - - get-nonce@1.0.1: - resolution: - { - integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==, - } - engines: { node: '>=6' } - - get-proto@1.0.1: - resolution: - { - integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==, - } - engines: { node: '>= 0.4' } - - glob-parent@5.1.2: - resolution: - { - integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, - } - engines: { node: '>= 6' } - - glob-parent@6.0.2: - resolution: - { - integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==, - } - engines: { node: '>=10.13.0' } - - glob@10.4.5: - resolution: - { - integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==, - } - hasBin: true - - glob@11.0.3: - resolution: - { - integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==, - } - engines: { node: 20 || >=22 } - hasBin: true - - globals@14.0.0: - resolution: - { - integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==, - } - engines: { node: '>=18' } - - gopd@1.2.0: - resolution: - { - integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==, - } - engines: { node: '>= 0.4' } - - graceful-fs@4.2.11: - resolution: - { - integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==, - } - - graphemer@1.4.0: - resolution: - { - integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==, - } - - graphlib@2.1.8: - resolution: - { - integrity: sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==, - } - - has-flag@4.0.0: - resolution: - { - integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, - } - engines: { node: '>=8' } - - has-symbols@1.1.0: - resolution: - { - integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==, - } - engines: { node: '>= 0.4' } - - has-tostringtag@1.0.2: - resolution: - { - integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==, - } - engines: { node: '>= 0.4' } - - hasown@2.0.2: - resolution: - { - integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==, - } - engines: { node: '>= 0.4' } - - hast-util-parse-selector@2.2.5: - resolution: - { - integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==, - } - - hastscript@6.0.0: - resolution: - { - integrity: sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==, - } - - highlight.js@10.7.3: - resolution: - { - integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==, - } - - highlightjs-vue@1.0.0: - resolution: - { - integrity: sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==, - } - - http-errors@2.0.0: - resolution: - { - integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==, - } - engines: { node: '>= 0.8' } - - iconv-lite@0.4.24: - resolution: - { - integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==, - } - engines: { node: '>=0.10.0' } - - iconv-lite@0.7.0: - resolution: - { - integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==, - } - engines: { node: '>=0.10.0' } - - ieee754@1.2.1: - resolution: - { - integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==, - } - - ignore@5.3.2: - resolution: - { - integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==, - } - engines: { node: '>= 4' } - - ignore@7.0.5: - resolution: - { - integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==, - } - engines: { node: '>= 4' } - - import-fresh@3.3.1: - resolution: - { - integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==, - } - engines: { node: '>=6' } - - imurmurhash@0.1.4: - resolution: - { - integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==, - } - engines: { node: '>=0.8.19' } - - inherits@2.0.4: - resolution: - { - integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==, - } - - inquirer@8.2.7: - resolution: - { - integrity: sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA==, - } - engines: { node: '>=12.0.0' } - - ipaddr.js@1.9.1: - resolution: - { - integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==, - } - engines: { node: '>= 0.10' } - - is-alphabetical@1.0.4: - resolution: - { - integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==, - } - - is-alphanumerical@1.0.4: - resolution: - { - integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==, - } - - is-decimal@1.0.4: - resolution: - { - integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==, - } - - is-extglob@2.1.1: - resolution: - { - integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, - } - engines: { node: '>=0.10.0' } - - is-fullwidth-code-point@3.0.0: - resolution: - { - integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==, - } - engines: { node: '>=8' } - - is-glob@4.0.3: - resolution: - { - integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, - } - engines: { node: '>=0.10.0' } - - is-hexadecimal@1.0.4: - resolution: - { - integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==, - } - - is-interactive@1.0.0: - resolution: - { - integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==, - } - engines: { node: '>=8' } - - is-number@7.0.0: - resolution: - { - integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, - } - engines: { node: '>=0.12.0' } - - is-stream@2.0.1: - resolution: - { - integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==, - } - engines: { node: '>=8' } - - is-unicode-supported@0.1.0: - resolution: - { - integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==, - } - engines: { node: '>=10' } - - isarray@1.0.0: - resolution: - { - integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==, - } - - isexe@2.0.0: - resolution: - { - integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, - } - - jackspeak@3.4.3: - resolution: - { - integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==, - } - - jackspeak@4.1.1: - resolution: - { - integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==, - } - engines: { node: 20 || >=22 } - - jiti@2.6.1: - resolution: - { - integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==, - } - hasBin: true - - js-tokens@4.0.0: - resolution: - { - integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, - } - - js-yaml@4.1.0: - resolution: - { - integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==, - } - hasBin: true - - jsesc@3.1.0: - resolution: - { - integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==, - } - engines: { node: '>=6' } - hasBin: true - - json-buffer@3.0.1: - resolution: - { - integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==, - } - - json-schema-traverse@0.4.1: - resolution: - { - integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==, - } - - json-schema-traverse@1.0.0: - resolution: - { - integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==, - } - - json-schema@0.4.0: - resolution: - { - integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==, - } - - json-stable-stringify-without-jsonify@1.0.1: - resolution: - { - integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==, - } - - json5@2.2.3: - resolution: - { - integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==, - } - engines: { node: '>=6' } - hasBin: true - - keyv@4.5.4: - resolution: - { - integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==, - } - - lazystream@1.0.1: - resolution: - { - integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==, - } - engines: { node: '>= 0.6.3' } - - levn@0.4.1: - resolution: - { - integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==, - } - engines: { node: '>= 0.8.0' } - - lightningcss-android-arm64@1.30.2: - resolution: - { - integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==, - } - engines: { node: '>= 12.0.0' } - cpu: [arm64] - os: [android] - - lightningcss-darwin-arm64@1.30.2: - resolution: - { - integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==, - } - engines: { node: '>= 12.0.0' } - cpu: [arm64] - os: [darwin] - - lightningcss-darwin-x64@1.30.2: - resolution: - { - integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==, - } - engines: { node: '>= 12.0.0' } - cpu: [x64] - os: [darwin] - - lightningcss-freebsd-x64@1.30.2: - resolution: - { - integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==, - } - engines: { node: '>= 12.0.0' } - cpu: [x64] - os: [freebsd] - - lightningcss-linux-arm-gnueabihf@1.30.2: - resolution: - { - integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==, - } - engines: { node: '>= 12.0.0' } - cpu: [arm] - os: [linux] - - lightningcss-linux-arm64-gnu@1.30.2: - resolution: - { - integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==, - } - engines: { node: '>= 12.0.0' } - cpu: [arm64] - os: [linux] - - lightningcss-linux-arm64-musl@1.30.2: - resolution: - { - integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==, - } - engines: { node: '>= 12.0.0' } - cpu: [arm64] - os: [linux] - - lightningcss-linux-x64-gnu@1.30.2: - resolution: - { - integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==, - } - engines: { node: '>= 12.0.0' } - cpu: [x64] - os: [linux] - - lightningcss-linux-x64-musl@1.30.2: - resolution: - { - integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==, - } - engines: { node: '>= 12.0.0' } - cpu: [x64] - os: [linux] - - lightningcss-win32-arm64-msvc@1.30.2: - resolution: - { - integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==, - } - engines: { node: '>= 12.0.0' } - cpu: [arm64] - os: [win32] - - lightningcss-win32-x64-msvc@1.30.2: - resolution: - { - integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==, - } - engines: { node: '>= 12.0.0' } - cpu: [x64] - os: [win32] - - lightningcss@1.30.2: - resolution: - { - integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==, - } - engines: { node: '>= 12.0.0' } - - locate-path@6.0.0: - resolution: - { - integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==, - } - engines: { node: '>=10' } - - lodash.merge@4.6.2: - resolution: - { - integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==, - } - - lodash.truncate@4.4.2: - resolution: - { - integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==, - } - - lodash@4.17.21: - resolution: - { - integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==, - } - - log-symbols@4.1.0: - resolution: - { - integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==, - } - engines: { node: '>=10' } - - lowlight@1.20.0: - resolution: - { - integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==, - } - - lru-cache@10.4.3: - resolution: - { - integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==, - } - - lru-cache@11.2.2: - resolution: - { - integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==, - } - engines: { node: 20 || >=22 } - - lru-cache@5.1.1: - resolution: - { - integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, - } - - lucide-react@0.510.0: - resolution: - { - integrity: sha512-p8SQRAMVh7NhsAIETokSqDrc5CHnDLbV29mMnzaXx+Vc/hnqQzwI2r0FMWCcoTXnbw2KEjy48xwpGdEL+ck06Q==, - } - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - lucide-react@0.525.0: - resolution: - { - integrity: sha512-Tm1txJ2OkymCGkvwoHt33Y2JpN5xucVq1slHcgE6Lk0WjDfjgKWor5CdVER8U6DvcfMwh4M8XxmpTiyzfmfDYQ==, - } - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - lucide-react@0.544.0: - resolution: - { - integrity: sha512-t5tS44bqd825zAW45UQxpG2CvcC4urOwn2TrwSH8u+MjeE+1NnWl6QqeQ/6NdjMqdOygyiT9p3Ev0p1NJykxjw==, - } - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - luxon@3.7.2: - resolution: - { - integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==, - } - engines: { node: '>=12' } - - magic-string@0.30.21: - resolution: - { - integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==, - } - - make-error@1.3.6: - resolution: - { - integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==, - } - - marked@14.0.0: - resolution: - { - integrity: sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==, - } - engines: { node: '>= 18' } - hasBin: true - - math-intrinsics@1.1.0: - resolution: - { - integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==, - } - engines: { node: '>= 0.4' } - - media-typer@0.3.0: - resolution: - { - integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==, - } - engines: { node: '>= 0.6' } - - merge-descriptors@1.0.3: - resolution: - { - integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==, - } - - merge2@1.4.1: - resolution: - { - integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==, - } - engines: { node: '>= 8' } - - methods@1.1.2: - resolution: - { - integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==, - } - engines: { node: '>= 0.6' } - - micromatch@4.0.8: - resolution: - { - integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==, - } - engines: { node: '>=8.6' } - - mime-db@1.52.0: - resolution: - { - integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==, - } - engines: { node: '>= 0.6' } - - mime-types@2.1.35: - resolution: - { - integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==, - } - engines: { node: '>= 0.6' } - - mime@1.6.0: - resolution: - { - integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==, - } - engines: { node: '>=4' } - hasBin: true - - mimic-fn@2.1.0: - resolution: - { - integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==, - } - engines: { node: '>=6' } - - minimatch@10.0.3: - resolution: - { - integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==, - } - engines: { node: 20 || >=22 } - - minimatch@3.1.2: - resolution: - { - integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, - } - - minimatch@5.1.6: - resolution: - { - integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==, - } - engines: { node: '>=10' } - - minimatch@9.0.5: - resolution: - { - integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==, - } - engines: { node: '>=16 || 14 >=14.17' } - - minimist@1.2.8: - resolution: - { - integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, - } - - minipass@7.1.2: - resolution: - { - integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==, - } - engines: { node: '>=16 || 14 >=14.17' } - - monaco-editor@0.54.0: - resolution: - { - integrity: sha512-hx45SEUoLatgWxHKCmlLJH81xBo0uXP4sRkESUpmDQevfi+e7K1VuiSprK6UpQ8u4zOcKNiH0pMvHvlMWA/4cw==, - } - - motia@0.8.2-beta.139: - resolution: - { - integrity: sha512-s3p9DElWBruak4ngqo8GODbHR5yab1pqLYPtYybmPumi44k0E5doD80lp0KbOYgZqVDCL0at4fsMqZgUfINnQg==, - } - hasBin: true - - ms@2.0.0: - resolution: - { - integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==, - } - - ms@2.1.3: - resolution: - { - integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, - } - - mute-stream@0.0.8: - resolution: - { - integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==, - } - - nanoid@3.3.11: - resolution: - { - integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==, - } - engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 } - hasBin: true - - natural-compare@1.4.0: - resolution: - { - integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==, - } - - negotiator@0.6.3: - resolution: - { - integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==, - } - engines: { node: '>= 0.6' } - - node-cron@3.0.3: - resolution: - { - integrity: sha512-dOal67//nohNgYWb+nWmg5dkFdIwDm8EpeGYMekPMrngV3637lqnX0lbUcCtgibHTz6SEz7DAIjKvKDFYCnO1A==, - } - engines: { node: '>=6.0.0' } - - node-releases@2.0.26: - resolution: - { - integrity: sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==, - } - - normalize-path@3.0.0: - resolution: - { - integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, - } - engines: { node: '>=0.10.0' } - - normalize-range@0.1.2: - resolution: - { - integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==, - } - engines: { node: '>=0.10.0' } - - object-inspect@1.13.4: - resolution: - { - integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==, - } - engines: { node: '>= 0.4' } - - on-finished@2.4.1: - resolution: - { - integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==, - } - engines: { node: '>= 0.8' } - - onetime@5.1.2: - resolution: - { - integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==, - } - engines: { node: '>=6' } - - optionator@0.9.4: - resolution: - { - integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==, - } - engines: { node: '>= 0.8.0' } - - ora@5.4.1: - resolution: - { - integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==, - } - engines: { node: '>=10' } - - p-limit@3.1.0: - resolution: - { - integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==, - } - engines: { node: '>=10' } - - p-locate@5.0.0: - resolution: - { - integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==, - } - engines: { node: '>=10' } - - package-json-from-dist@1.0.1: - resolution: - { - integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==, - } - - parent-module@1.0.1: - resolution: - { - integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, - } - engines: { node: '>=6' } - - parse-entities@2.0.0: - resolution: - { - integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==, - } - - parseurl@1.3.3: - resolution: - { - integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==, - } - engines: { node: '>= 0.8' } - - path-exists@4.0.0: - resolution: - { - integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==, - } - engines: { node: '>=8' } - - path-key@3.1.1: - resolution: - { - integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, - } - engines: { node: '>=8' } - - path-scurry@1.11.1: - resolution: - { - integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==, - } - engines: { node: '>=16 || 14 >=14.18' } - - path-scurry@2.0.0: - resolution: - { - integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==, - } - engines: { node: 20 || >=22 } - - path-to-regexp@0.1.12: - resolution: - { - integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==, - } - - picocolors@1.1.1: - resolution: - { - integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==, - } - - picomatch@2.3.1: - resolution: - { - integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, - } - engines: { node: '>=8.6' } - - picomatch@4.0.3: - resolution: - { - integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==, - } - engines: { node: '>=12' } - - postcss-value-parser@4.2.0: - resolution: - { - integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==, - } - - postcss@8.5.6: - resolution: - { - integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==, - } - engines: { node: ^10 || ^12 || >=14 } - - prelude-ls@1.2.1: - resolution: - { - integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==, - } - engines: { node: '>= 0.8.0' } - - prismjs@1.27.0: - resolution: - { - integrity: sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==, - } - engines: { node: '>=6' } - - prismjs@1.30.0: - resolution: - { - integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==, - } - engines: { node: '>=6' } - - process-nextick-args@2.0.1: - resolution: - { - integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==, - } - - process@0.11.10: - resolution: - { - integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==, - } - engines: { node: '>= 0.6.0' } - - property-information@5.6.0: - resolution: - { - integrity: sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==, - } - - proxy-addr@2.0.7: - resolution: - { - integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==, - } - engines: { node: '>= 0.10' } - - proxy-from-env@1.1.0: - resolution: - { - integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==, - } - - punycode@2.3.1: - resolution: - { - integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, - } - engines: { node: '>=6' } - - python-ast@0.1.0: - resolution: - { - integrity: sha512-uMPE7HRMfsbHtQYPg/+EH9MJkynLfLr+0VJbeBgJHpt2wuDgf5hZrEczOIGNFKaO0W1HWiL7bSxA/EOOo70mIQ==, - } - - qs@6.13.0: - resolution: - { - integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==, - } - engines: { node: '>=0.6' } - - queue-microtask@1.2.3: - resolution: - { - integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, - } - - range-parser@1.2.1: - resolution: - { - integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==, - } - engines: { node: '>= 0.6' } - - raw-body@2.5.2: - resolution: - { - integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==, - } - engines: { node: '>= 0.8' } - - react-dom@19.2.0: - resolution: - { - integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==, - } - peerDependencies: - react: ^19.2.0 - - react-refresh@0.17.0: - resolution: - { - integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==, - } - engines: { node: '>=0.10.0' } - - react-remove-scroll-bar@2.3.8: - resolution: - { - integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==, - } - engines: { node: '>=10' } - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - react-remove-scroll@2.7.1: - resolution: - { - integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==, - } - engines: { node: '>=10' } - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - react-resizable-panels@3.0.6: - resolution: - { - integrity: sha512-b3qKHQ3MLqOgSS+FRYKapNkJZf5EQzuf6+RLiq1/IlTHw99YrZ2NJZLk4hQIzTnnIkRg2LUqyVinu6YWWpUYew==, - } - peerDependencies: - react: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - - react-style-singleton@2.2.3: - resolution: - { - integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==, - } - engines: { node: '>=10' } - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - react-syntax-highlighter@15.6.6: - resolution: - { - integrity: sha512-DgXrc+AZF47+HvAPEmn7Ua/1p10jNoVZVI/LoPiYdtY+OM+/nG5yefLHKJwdKqY1adMuHFbeyBaG9j64ML7vTw==, - } - peerDependencies: - react: '>= 0.14.0' - - react-use-resizable@0.2.0: - resolution: - { - integrity: sha512-gp1cSSNzRDuRouWTYYxKE7f8VC/4cqdGpgbN9rDNdaFSwCfze/ki+WJL0Zouab/HILDpfIGW2JqAz94VmfroLA==, - } - peerDependencies: - react: '>=16.8.0' - - react18-json-view@0.2.9: - resolution: - { - integrity: sha512-z3JQgCwZRKbmWh54U94loCU6vE0ZoDBK7C8ZpcMYQB8jYMi+mR/fcgMI9jKgATeF0I6+OAF025PD+UKkXIqueQ==, - } - peerDependencies: - react: '>=16.8.0' - - react@19.2.0: - resolution: - { - integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==, - } - engines: { node: '>=0.10.0' } - - readable-stream@2.3.8: - resolution: - { - integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==, - } - - readable-stream@3.6.2: - resolution: - { - integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==, - } - engines: { node: '>= 6' } - - readable-stream@4.7.0: - resolution: - { - integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==, - } - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } - - readdir-glob@1.1.3: - resolution: - { - integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==, - } - - readdirp@4.1.2: - resolution: - { - integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==, - } - engines: { node: '>= 14.18.0' } - - refractor@3.6.0: - resolution: - { - integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==, - } - - require-from-string@2.0.2: - resolution: - { - integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==, - } - engines: { node: '>=0.10.0' } - - resolve-from@4.0.0: - resolution: - { - integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, - } - engines: { node: '>=4' } - - restore-cursor@3.1.0: - resolution: - { - integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==, - } - engines: { node: '>=8' } - - reusify@1.1.0: - resolution: - { - integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==, - } - engines: { iojs: '>=1.0.0', node: '>=0.10.0' } - - rollup@4.52.5: - resolution: - { - integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==, - } - engines: { node: '>=18.0.0', npm: '>=8.0.0' } - hasBin: true - - run-async@2.4.1: - resolution: - { - integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==, - } - engines: { node: '>=0.12.0' } - - run-parallel@1.2.0: - resolution: - { - integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==, - } - - rxjs@7.8.2: - resolution: - { - integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==, - } - - safe-buffer@5.1.2: - resolution: - { - integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==, - } - - safe-buffer@5.2.1: - resolution: - { - integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==, - } - - safer-buffer@2.1.2: - resolution: - { - integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==, - } - - scheduler@0.27.0: - resolution: - { - integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==, - } - - semver@6.3.1: - resolution: - { - integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, - } - hasBin: true - - semver@7.7.3: - resolution: - { - integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==, - } - engines: { node: '>=10' } - hasBin: true - - send@0.19.0: - resolution: - { - integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==, - } - engines: { node: '>= 0.8.0' } - - serve-static@1.16.2: - resolution: - { - integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==, - } - engines: { node: '>= 0.8.0' } - - setprototypeof@1.2.0: - resolution: - { - integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==, - } - - shebang-command@2.0.0: - resolution: - { - integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, - } - engines: { node: '>=8' } - - shebang-regex@3.0.0: - resolution: - { - integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, - } - engines: { node: '>=8' } - - side-channel-list@1.0.0: - resolution: - { - integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==, - } - engines: { node: '>= 0.4' } - - side-channel-map@1.0.1: - resolution: - { - integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==, - } - engines: { node: '>= 0.4' } - - side-channel-weakmap@1.0.2: - resolution: - { - integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==, - } - engines: { node: '>= 0.4' } - - side-channel@1.1.0: - resolution: - { - integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==, - } - engines: { node: '>= 0.4' } - - signal-exit@3.0.7: - resolution: - { - integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==, - } - - signal-exit@4.1.0: - resolution: - { - integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==, - } - engines: { node: '>=14' } - - slice-ansi@4.0.0: - resolution: - { - integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==, - } - engines: { node: '>=10' } - - source-map-js@1.2.1: - resolution: - { - integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==, - } - engines: { node: '>=0.10.0' } - - space-separated-tokens@1.1.5: - resolution: - { - integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==, - } - - state-local@1.0.7: - resolution: - { - integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==, - } - - statuses@2.0.1: - resolution: - { - integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==, - } - engines: { node: '>= 0.8' } - - streamx@2.23.0: - resolution: - { - integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==, - } - - string-width@4.2.3: - resolution: - { - integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==, - } - engines: { node: '>=8' } - - string-width@5.1.2: - resolution: - { - integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==, - } - engines: { node: '>=12' } - - string_decoder@1.1.1: - resolution: - { - integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==, - } - - string_decoder@1.3.0: - resolution: - { - integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==, - } - - strip-ansi@6.0.1: - resolution: - { - integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, - } - engines: { node: '>=8' } - - strip-ansi@7.1.2: - resolution: - { - integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==, - } - engines: { node: '>=12' } - - strip-bom@3.0.0: - resolution: - { - integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==, - } - engines: { node: '>=4' } - - strip-json-comments@3.1.1: - resolution: - { - integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, - } - engines: { node: '>=8' } - - supports-color@7.2.0: - resolution: - { - integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, - } - engines: { node: '>=8' } - - table@6.9.0: - resolution: - { - integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==, - } - engines: { node: '>=10.0.0' } - - tailwind-merge@3.3.1: - resolution: - { - integrity: sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==, - } - - tailwindcss@4.1.16: - resolution: - { - integrity: sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA==, - } - - tapable@2.3.0: - resolution: - { - integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==, - } - engines: { node: '>=6' } - - tar-stream@3.1.7: - resolution: - { - integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==, - } - - text-decoder@1.2.3: - resolution: - { - integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==, - } - - through@2.3.8: - resolution: - { - integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==, - } - - tinyglobby@0.2.15: - resolution: - { - integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==, - } - engines: { node: '>=12.0.0' } - - to-regex-range@5.0.1: - resolution: - { - integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, - } - engines: { node: '>=8.0' } - - toggle-selection@1.0.6: - resolution: - { - integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==, - } - - toidentifier@1.0.1: - resolution: - { - integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==, - } - engines: { node: '>=0.6' } - - ts-api-utils@2.1.0: - resolution: - { - integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==, - } - engines: { node: '>=18.12' } - peerDependencies: - typescript: '>=4.8.4' - - ts-node@10.9.2: - resolution: - { - integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==, - } - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - - tsconfig-paths@4.2.0: - resolution: - { - integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==, - } - engines: { node: '>=6' } - - tslib@2.8.1: - resolution: - { - integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==, - } - - tw-animate-css@1.4.0: - resolution: - { - integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==, - } - - type-check@0.4.0: - resolution: - { - integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==, - } - engines: { node: '>= 0.8.0' } - - type-fest@0.21.3: - resolution: - { - integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==, - } - engines: { node: '>=10' } - - type-is@1.6.18: - resolution: - { - integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==, - } - engines: { node: '>= 0.6' } - - typescript-eslint@8.46.2: - resolution: - { - integrity: sha512-vbw8bOmiuYNdzzV3lsiWv6sRwjyuKJMQqWulBOU7M0RrxedXledX8G8kBbQeiOYDnTfiXz0Y4081E1QMNB6iQg==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - typescript@5.8.3: - resolution: - { - integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==, - } - engines: { node: '>=14.17' } - hasBin: true - - typescript@5.9.3: - resolution: - { - integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==, - } - engines: { node: '>=14.17' } - hasBin: true - - undici-types@7.16.0: - resolution: - { - integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==, - } - - unpipe@1.0.0: - resolution: - { - integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==, - } - engines: { node: '>= 0.8' } - - update-browserslist-db@1.1.4: - resolution: - { - integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==, - } - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - uri-js@4.4.1: - resolution: - { - integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, - } - - use-callback-ref@1.3.3: - resolution: - { - integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==, - } - engines: { node: '>=10' } - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - use-sidecar@1.1.3: - resolution: - { - integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==, - } - engines: { node: '>=10' } - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - use-sync-external-store@1.6.0: - resolution: - { - integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==, - } - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - util-deprecate@1.0.2: - resolution: - { - integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, - } - - utils-merge@1.0.1: - resolution: - { - integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==, - } - engines: { node: '>= 0.4.0' } - - uuid@11.1.0: - resolution: - { - integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==, - } - hasBin: true - - uuid@8.3.2: - resolution: - { - integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==, - } - hasBin: true - - v8-compile-cache-lib@3.0.1: - resolution: - { - integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==, - } - - vary@1.1.2: - resolution: - { - integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==, - } - engines: { node: '>= 0.8' } - - vite@6.4.1: - resolution: - { - integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==, - } - engines: { node: ^18.0.0 || ^20.0.0 || >=22.0.0 } - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - jiti: '>=1.21.0' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - wcwidth@1.0.1: - resolution: - { - integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==, - } - - which@2.0.2: - resolution: - { - integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, - } - engines: { node: '>= 8' } - hasBin: true - - word-wrap@1.2.5: - resolution: - { - integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==, - } - engines: { node: '>=0.10.0' } - - wrap-ansi@6.2.0: - resolution: - { - integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==, - } - engines: { node: '>=8' } - - wrap-ansi@7.0.0: - resolution: - { - integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==, - } - engines: { node: '>=10' } - - wrap-ansi@8.1.0: - resolution: - { - integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==, - } - engines: { node: '>=12' } - - ws@8.18.3: - resolution: - { - integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==, - } - 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 - - xtend@4.0.2: - resolution: - { - integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==, - } - engines: { node: '>=0.4' } - - yallist@3.1.1: - resolution: - { - integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==, - } - - yn@3.1.1: - resolution: - { - integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==, - } - engines: { node: '>=6' } - - yocto-queue@0.1.0: - resolution: - { - integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, - } - engines: { node: '>=10' } - - zip-stream@6.0.1: - resolution: - { - integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==, - } - engines: { node: '>= 14' } - - zod-to-json-schema@3.24.6: - resolution: - { - integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==, - } - peerDependencies: - zod: ^3.24.1 - - zod@3.25.76: - resolution: - { - integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==, - } - - zustand@4.5.7: - resolution: - { - integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==, - } - engines: { node: '>=12.7.0' } - peerDependencies: - '@types/react': '>=16.8' - immer: '>=9.0.6' - react: '>=16.8' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - - zustand@5.0.8: - resolution: - { - integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==, - } - engines: { node: '>=12.20.0' } - peerDependencies: - '@types/react': '>=18.0.0' - immer: '>=9.0.6' - react: '>=18.0.0' - use-sync-external-store: '>=1.2.0' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - use-sync-external-store: - optional: true - -snapshots: - '@alloc/quick-lru@5.2.0': {} - - '@amplitude/analytics-connector@1.6.4': {} - - '@amplitude/analytics-core@2.30.0': - dependencies: - '@amplitude/analytics-connector': 1.6.4 - tslib: 2.8.1 - - '@amplitude/analytics-node@1.5.20': - dependencies: - '@amplitude/analytics-core': 2.30.0 - tslib: 2.8.1 - - '@babel/code-frame@7.27.1': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.28.5': {} - - '@babel/core@7.28.5': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.28.5': - dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-compilation-targets@7.27.2': - dependencies: - '@babel/compat-data': 7.28.5 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.27.0 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-module-imports@7.27.1': - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-plugin-utils@7.27.1': {} - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.28.5': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.28.4': - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 - - '@babel/parser@7.28.5': - dependencies: - '@babel/types': 7.28.5 - - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/runtime@7.28.4': {} - - '@babel/template@7.27.2': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - - '@babel/traverse@7.28.5': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.28.5': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - '@cspotcode/source-map-support@0.8.1': - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - - '@esbuild/aix-ppc64@0.25.11': - optional: true - - '@esbuild/android-arm64@0.25.11': - optional: true - - '@esbuild/android-arm@0.25.11': - optional: true - - '@esbuild/android-x64@0.25.11': - optional: true - - '@esbuild/darwin-arm64@0.25.11': - optional: true - - '@esbuild/darwin-x64@0.25.11': - optional: true - - '@esbuild/freebsd-arm64@0.25.11': - optional: true - - '@esbuild/freebsd-x64@0.25.11': - optional: true - - '@esbuild/linux-arm64@0.25.11': - optional: true - - '@esbuild/linux-arm@0.25.11': - optional: true - - '@esbuild/linux-ia32@0.25.11': - optional: true - - '@esbuild/linux-loong64@0.25.11': - optional: true - - '@esbuild/linux-mips64el@0.25.11': - optional: true - - '@esbuild/linux-ppc64@0.25.11': - optional: true - - '@esbuild/linux-riscv64@0.25.11': - optional: true - - '@esbuild/linux-s390x@0.25.11': - optional: true - - '@esbuild/linux-x64@0.25.11': - optional: true - - '@esbuild/netbsd-arm64@0.25.11': - optional: true - - '@esbuild/netbsd-x64@0.25.11': - optional: true - - '@esbuild/openbsd-arm64@0.25.11': - optional: true - - '@esbuild/openbsd-x64@0.25.11': - optional: true - - '@esbuild/openharmony-arm64@0.25.11': - optional: true - - '@esbuild/sunos-x64@0.25.11': - optional: true - - '@esbuild/win32-arm64@0.25.11': - optional: true - - '@esbuild/win32-ia32@0.25.11': - optional: true - - '@esbuild/win32-x64@0.25.11': - optional: true - - '@eslint-community/eslint-utils@4.9.0(eslint@9.38.0(jiti@2.6.1))': - dependencies: - eslint: 9.38.0(jiti@2.6.1) - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.2': {} - - '@eslint/config-array@0.21.1': - dependencies: - '@eslint/object-schema': 2.1.7 - debug: 4.4.3 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - - '@eslint/config-helpers@0.4.1': - dependencies: - '@eslint/core': 0.16.0 - - '@eslint/core@0.16.0': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/eslintrc@3.3.1': - dependencies: - ajv: 6.12.6 - debug: 4.4.3 - espree: 10.4.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@9.38.0': {} - - '@eslint/object-schema@2.1.7': {} - - '@eslint/plugin-kit@0.4.0': - dependencies: - '@eslint/core': 0.16.0 - levn: 0.4.1 - - '@floating-ui/core@1.7.3': - dependencies: - '@floating-ui/utils': 0.2.10 - - '@floating-ui/dom@1.7.4': - dependencies: - '@floating-ui/core': 1.7.3 - '@floating-ui/utils': 0.2.10 - - '@floating-ui/react-dom@2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@floating-ui/dom': 1.7.4 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - - '@floating-ui/utils@0.2.10': {} - - '@humanfs/core@0.19.1': {} - - '@humanfs/node@0.16.7': - dependencies: - '@humanfs/core': 0.19.1 - '@humanwhocodes/retry': 0.4.3 - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/retry@0.4.3': {} - - '@inquirer/external-editor@1.0.2(@types/node@24.9.1)': - dependencies: - chardet: 2.1.0 - iconv-lite: 0.7.0 - optionalDependencies: - '@types/node': 24.9.1 - - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.0': - dependencies: - '@isaacs/balanced-match': 4.0.1 - - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.2 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@jridgewell/trace-mapping@0.3.9': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@monaco-editor/loader@1.6.1': - dependencies: - state-local: 1.0.7 - - '@monaco-editor/react@4.7.0(monaco-editor@0.54.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@monaco-editor/loader': 1.6.1 - monaco-editor: 0.54.0 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - - '@motiadev/core@0.8.2-beta.139(@types/node@24.9.1)(typescript@5.9.3)': - dependencies: - '@amplitude/analytics-node': 1.5.20 - body-parser: 1.20.3 - colors: 1.4.0 - dotenv: 16.6.1 - express: 4.21.2 - node-cron: 3.0.3 - ts-node: 10.9.2(@types/node@24.9.1)(typescript@5.9.3) - tsconfig-paths: 4.2.0 - uuid: 11.1.0 - ws: 8.18.3 - zod: 3.25.76 - zod-to-json-schema: 3.24.6(zod@3.25.76) - transitivePeerDependencies: - - '@swc/core' - - '@swc/wasm' - - '@types/node' - - bufferutil - - supports-color - - typescript - - utf-8-validate - - '@motiadev/plugin-endpoint@0.8.2-beta.139(@types/react@18.3.26)(monaco-editor@0.54.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0))': - dependencies: - '@monaco-editor/react': 4.7.0(monaco-editor@0.54.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@motiadev/stream-client-react': 0.8.2-beta.139(react@19.2.0) - '@motiadev/ui': 0.8.2-beta.139(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) - clsx: 2.1.1 - json-schema: 0.4.0 - lucide-react: 0.544.0(react@19.2.0) - react18-json-view: 0.2.9(react@19.2.0) - tailwind-merge: 3.3.1 - zustand: 5.0.8(@types/react@18.3.26)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' - - immer - - monaco-editor - - react - - react-dom - - use-sync-external-store - - '@motiadev/stream-client-browser@0.8.2-beta.139': - dependencies: - '@motiadev/stream-client': 0.8.2-beta.139 - uuid: 11.1.0 - - '@motiadev/stream-client-node@0.8.2-beta.139': - dependencies: - '@motiadev/stream-client': 0.8.2-beta.139 - uuid: 11.1.0 - ws: 8.18.3 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@motiadev/stream-client-react@0.8.2-beta.139(react@19.2.0)': - dependencies: - '@motiadev/stream-client-browser': 0.8.2-beta.139 - react: 19.2.0 - - '@motiadev/stream-client@0.8.2-beta.139': - dependencies: - uuid: 11.1.0 - - '@motiadev/ui@0.8.2-beta.139(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0))': - dependencies: - '@radix-ui/react-checkbox': 1.3.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-dropdown-menu': 2.1.16(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-label': 2.1.7(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-select': 2.2.6(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-separator': 1.1.7(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-tabs': 1.1.13(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-tooltip': 1.2.8(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - class-variance-authority: 0.7.1 - clsx: 2.1.1 - lucide-react: 0.525.0(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - react-resizable-panels: 3.0.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react-use-resizable: 0.2.0(react@19.2.0) - tailwind-merge: 3.3.1 - zustand: 5.0.8(@types/react@18.3.26)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' - - immer - - use-sync-external-store - - '@motiadev/workbench@0.8.2-beta.139(@types/node@24.9.1)(@types/react@18.3.26)(eslint@9.38.0(jiti@2.6.1))(jiti@2.6.1)(lightningcss@1.30.2)(monaco-editor@0.54.0)(use-sync-external-store@1.6.0(react@19.2.0))': - dependencies: - '@monaco-editor/react': 4.7.0(monaco-editor@0.54.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@motiadev/plugin-endpoint': 0.8.2-beta.139(@types/react@18.3.26)(monaco-editor@0.54.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) - '@motiadev/stream-client-react': 0.8.2-beta.139(react@19.2.0) - '@motiadev/ui': 0.8.2-beta.139(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) - '@radix-ui/react-collapsible': 1.1.12(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-dialog': 1.1.15(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-dropdown-menu': 2.1.16(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-label': 2.1.7(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-navigation-menu': 1.2.14(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-scroll-area': 1.2.10(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-select': 2.2.6(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-separator': 1.1.7(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-switch': 1.2.6(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-tabs': 1.1.13(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-tooltip': 1.2.8(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@tailwindcss/postcss': 4.1.16 - '@vitejs/plugin-react': 4.7.0(vite@6.4.1(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.30.2)) - '@xyflow/react': 12.9.0(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - autoprefixer: 10.4.21(postcss@8.5.6) - class-variance-authority: 0.7.1 - clsx: 2.1.1 - dagre: 0.8.5 - date-fns: 4.1.0 - fast-deep-equal: 3.1.3 - json-schema: 0.4.0 - lucide-react: 0.510.0(react@19.2.0) - postcss: 8.5.6 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - react-syntax-highlighter: 15.6.6(react@19.2.0) - react-use-resizable: 0.2.0(react@19.2.0) - react18-json-view: 0.2.9(react@19.2.0) - tailwind-merge: 3.3.1 - tailwindcss: 4.1.16 - tw-animate-css: 1.4.0 - typescript: 5.8.3 - typescript-eslint: 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3) - vite: 6.4.1(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.30.2) - zustand: 5.0.8(@types/react@18.3.26)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) - transitivePeerDependencies: - - '@types/node' - - '@types/react' - - '@types/react-dom' - - eslint - - immer - - jiti - - less - - lightningcss - - monaco-editor - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - use-sync-external-store - - yaml - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.1 - - '@pkgjs/parseargs@0.11.0': - optional: true - - '@radix-ui/number@1.1.1': {} - - '@radix-ui/primitive@1.1.3': {} - - '@radix-ui/react-arrow@1.1.7(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-checkbox@1.3.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-collapsible@1.1.12(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-collection@1.1.7(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.26)(react@19.2.0)': - dependencies: - react: 19.2.0 - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-context@1.1.2(@types/react@18.3.26)(react@19.2.0)': - dependencies: - react: 19.2.0 - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-dialog@1.1.15(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-focus-scope': 1.1.7(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-portal': 1.1.9(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.26)(react@19.2.0) - aria-hidden: 1.2.6 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - react-remove-scroll: 2.7.1(@types/react@18.3.26)(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-direction@1.1.1(@types/react@18.3.26)(react@19.2.0)': - dependencies: - react: 19.2.0 - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-dismissable-layer@1.1.11(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-dropdown-menu@2.1.16(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-menu': 2.1.16(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-focus-guards@1.1.3(@types/react@18.3.26)(react@19.2.0)': - dependencies: - react: 19.2.0 - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-focus-scope@1.1.7(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-id@1.1.1(@types/react@18.3.26)(react@19.2.0)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-label@2.1.7(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-menu@2.1.16(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-focus-scope': 1.1.7(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-popper': 1.2.8(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-portal': 1.1.9(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-roving-focus': 1.1.11(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.26)(react@19.2.0) - aria-hidden: 1.2.6 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - react-remove-scroll: 2.7.1(@types/react@18.3.26)(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-navigation-menu@1.2.14(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-popper@1.2.8(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@floating-ui/react-dom': 2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-arrow': 1.1.7(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-rect': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/rect': 1.1.1 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-portal@1.1.9(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-presence@1.1.5(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-primitive@2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-roving-focus@1.1.11(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-scroll-area@1.2.10(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-select@2.2.6(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-focus-scope': 1.1.7(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-popper': 1.2.8(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-portal': 1.1.9(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - aria-hidden: 1.2.6 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - react-remove-scroll: 2.7.1(@types/react@18.3.26)(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-separator@1.1.7(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-slot@1.2.3(@types/react@18.3.26)(react@19.2.0)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-switch@1.2.6(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-tabs@1.1.13(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-roving-focus': 1.1.11(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-tooltip@1.2.8(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-popper': 1.2.8(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-portal': 1.1.9(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.3.26)(react@19.2.0)': - dependencies: - react: 19.2.0 - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@18.3.26)(react@19.2.0)': - dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.3.26)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-use-effect-event@0.0.2(@types/react@18.3.26)(react@19.2.0)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@18.3.26)(react@19.2.0)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@18.3.26)(react@19.2.0)': - dependencies: - react: 19.2.0 - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-use-previous@1.1.1(@types/react@18.3.26)(react@19.2.0)': - dependencies: - react: 19.2.0 - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-use-rect@1.1.1(@types/react@18.3.26)(react@19.2.0)': - dependencies: - '@radix-ui/rect': 1.1.1 - react: 19.2.0 - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-use-size@1.1.1(@types/react@18.3.26)(react@19.2.0)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) - react: 19.2.0 - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/react-visually-hidden@1.2.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - '@radix-ui/rect@1.1.1': {} - - '@rolldown/pluginutils@1.0.0-beta.27': {} - - '@rollup/rollup-android-arm-eabi@4.52.5': - optional: true - - '@rollup/rollup-android-arm64@4.52.5': - optional: true - - '@rollup/rollup-darwin-arm64@4.52.5': - optional: true - - '@rollup/rollup-darwin-x64@4.52.5': - optional: true - - '@rollup/rollup-freebsd-arm64@4.52.5': - optional: true - - '@rollup/rollup-freebsd-x64@4.52.5': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.52.5': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.52.5': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.52.5': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.52.5': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.52.5': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.52.5': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.52.5': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.52.5': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.52.5': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.52.5': - optional: true - - '@rollup/rollup-linux-x64-musl@4.52.5': - optional: true - - '@rollup/rollup-openharmony-arm64@4.52.5': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.52.5': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.52.5': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.52.5': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.52.5': - optional: true - - '@tailwindcss/node@4.1.16': - dependencies: - '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.18.3 - jiti: 2.6.1 - lightningcss: 1.30.2 - magic-string: 0.30.21 - source-map-js: 1.2.1 - tailwindcss: 4.1.16 - - '@tailwindcss/oxide-android-arm64@4.1.16': - optional: true - - '@tailwindcss/oxide-darwin-arm64@4.1.16': - optional: true - - '@tailwindcss/oxide-darwin-x64@4.1.16': - optional: true - - '@tailwindcss/oxide-freebsd-x64@4.1.16': - optional: true - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.16': - optional: true - - '@tailwindcss/oxide-linux-arm64-gnu@4.1.16': - optional: true - - '@tailwindcss/oxide-linux-arm64-musl@4.1.16': - optional: true - - '@tailwindcss/oxide-linux-x64-gnu@4.1.16': - optional: true - - '@tailwindcss/oxide-linux-x64-musl@4.1.16': - optional: true - - '@tailwindcss/oxide-wasm32-wasi@4.1.16': - optional: true - - '@tailwindcss/oxide-win32-arm64-msvc@4.1.16': - optional: true - - '@tailwindcss/oxide-win32-x64-msvc@4.1.16': - optional: true - - '@tailwindcss/oxide@4.1.16': - optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.16 - '@tailwindcss/oxide-darwin-arm64': 4.1.16 - '@tailwindcss/oxide-darwin-x64': 4.1.16 - '@tailwindcss/oxide-freebsd-x64': 4.1.16 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.16 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.16 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.16 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.16 - '@tailwindcss/oxide-linux-x64-musl': 4.1.16 - '@tailwindcss/oxide-wasm32-wasi': 4.1.16 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.16 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.16 - - '@tailwindcss/postcss@4.1.16': - dependencies: - '@alloc/quick-lru': 5.2.0 - '@tailwindcss/node': 4.1.16 - '@tailwindcss/oxide': 4.1.16 - postcss: 8.5.6 - tailwindcss: 4.1.16 - - '@tsconfig/node10@1.0.11': {} - - '@tsconfig/node12@1.0.11': {} - - '@tsconfig/node14@1.0.3': {} - - '@tsconfig/node16@1.0.4': {} - - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 - - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.28.5 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - - '@types/babel__traverse@7.28.0': - dependencies: - '@babel/types': 7.28.5 - - '@types/d3-color@3.1.3': {} - - '@types/d3-drag@3.0.7': - dependencies: - '@types/d3-selection': 3.0.11 - - '@types/d3-interpolate@3.0.4': - dependencies: - '@types/d3-color': 3.1.3 - - '@types/d3-selection@3.0.11': {} - - '@types/d3-transition@3.0.9': - dependencies: - '@types/d3-selection': 3.0.11 - - '@types/d3-zoom@3.0.8': - dependencies: - '@types/d3-interpolate': 3.0.4 - '@types/d3-selection': 3.0.11 - - '@types/estree@1.0.8': {} - - '@types/hast@2.3.10': - dependencies: - '@types/unist': 2.0.11 - - '@types/json-schema@7.0.15': {} - - '@types/luxon@3.7.1': {} - - '@types/node@24.9.1': - dependencies: - undici-types: 7.16.0 - - '@types/prop-types@15.7.15': {} - - '@types/react@18.3.26': - dependencies: - '@types/prop-types': 15.7.15 - csstype: 3.1.3 - - '@types/unist@2.0.11': {} - - '@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.46.2 - '@typescript-eslint/type-utils': 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3) - '@typescript-eslint/utils': 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.46.2 - eslint: 9.38.0(jiti@2.6.1) - graphemer: 1.4.0 - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.46.2 - '@typescript-eslint/types': 8.46.2 - '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.46.2 - debug: 4.4.3 - eslint: 9.38.0(jiti@2.6.1) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/project-service@8.46.2(typescript@5.8.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.8.3) - '@typescript-eslint/types': 8.46.2 - debug: 4.4.3 - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@8.46.2': - dependencies: - '@typescript-eslint/types': 8.46.2 - '@typescript-eslint/visitor-keys': 8.46.2 - - '@typescript-eslint/tsconfig-utils@8.46.2(typescript@5.8.3)': - dependencies: - typescript: 5.8.3 - - '@typescript-eslint/type-utils@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3)': - dependencies: - '@typescript-eslint/types': 8.46.2 - '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.8.3) - '@typescript-eslint/utils': 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3) - debug: 4.4.3 - eslint: 9.38.0(jiti@2.6.1) - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@8.46.2': {} - - '@typescript-eslint/typescript-estree@8.46.2(typescript@5.8.3)': - dependencies: - '@typescript-eslint/project-service': 8.46.2(typescript@5.8.3) - '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.8.3) - '@typescript-eslint/types': 8.46.2 - '@typescript-eslint/visitor-keys': 8.46.2 - debug: 4.4.3 - fast-glob: 3.3.3 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.3 - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.46.2 - '@typescript-eslint/types': 8.46.2 - '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.8.3) - eslint: 9.38.0(jiti@2.6.1) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/visitor-keys@8.46.2': - dependencies: - '@typescript-eslint/types': 8.46.2 - eslint-visitor-keys: 4.2.1 - - '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.30.2))': - dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5) - '@rolldown/pluginutils': 1.0.0-beta.27 - '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 6.4.1(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.30.2) - transitivePeerDependencies: - - supports-color - - '@xyflow/react@12.9.0(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@xyflow/system': 0.0.71 - classcat: 5.0.5 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - zustand: 4.5.7(@types/react@18.3.26)(react@19.2.0) - transitivePeerDependencies: - - '@types/react' - - immer - - '@xyflow/system@0.0.71': - dependencies: - '@types/d3-drag': 3.0.7 - '@types/d3-interpolate': 3.0.4 - '@types/d3-selection': 3.0.11 - '@types/d3-transition': 3.0.9 - '@types/d3-zoom': 3.0.8 - d3-drag: 3.0.0 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-zoom: 3.0.0 - - abort-controller@3.0.0: - dependencies: - event-target-shim: 5.0.1 - - accepts@1.3.8: - dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 - - acorn-jsx@5.3.2(acorn@8.15.0): - dependencies: - acorn: 8.15.0 - - acorn-walk@8.3.4: - dependencies: - acorn: 8.15.0 - - acorn@8.15.0: {} - - ajv@6.12.6: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ajv@8.17.1: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - - ansi-escapes@4.3.2: - dependencies: - type-fest: 0.21.3 - - ansi-regex@5.0.1: {} - - ansi-regex@6.2.2: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@6.2.3: {} - - antlr4ts@0.5.0-alpha.4: {} - - archiver-utils@5.0.2: - dependencies: - glob: 10.4.5 - graceful-fs: 4.2.11 - is-stream: 2.0.1 - lazystream: 1.0.1 - lodash: 4.17.21 - normalize-path: 3.0.0 - readable-stream: 4.7.0 - - archiver@7.0.1: - dependencies: - archiver-utils: 5.0.2 - async: 3.2.6 - buffer-crc32: 1.0.0 - readable-stream: 4.7.0 - readdir-glob: 1.1.3 - tar-stream: 3.1.7 - zip-stream: 6.0.1 - transitivePeerDependencies: - - bare-abort-controller - - react-native-b4a - - arg@4.1.3: {} - - argparse@2.0.1: {} - - aria-hidden@1.2.6: - dependencies: - tslib: 2.8.1 - - array-flatten@1.1.1: {} - - astral-regex@2.0.0: {} - - async@3.2.6: {} - - asynckit@0.4.0: {} - - autoprefixer@10.4.21(postcss@8.5.6): - dependencies: - browserslist: 4.27.0 - caniuse-lite: 1.0.30001751 - fraction.js: 4.3.7 - normalize-range: 0.1.2 - picocolors: 1.1.1 - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - - axios@1.12.2: - dependencies: - follow-redirects: 1.15.11 - form-data: 4.0.4 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - - b4a@1.7.3: {} - - balanced-match@1.0.2: {} - - bare-events@2.8.1: {} - - base64-js@1.5.1: {} - - baseline-browser-mapping@2.8.20: {} - - bl@4.1.0: - dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.2 - - body-parser@1.20.3: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.13.0 - raw-body: 2.5.2 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - - brace-expansion@1.1.12: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.0.2: - dependencies: - balanced-match: 1.0.2 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - browserslist@4.27.0: - dependencies: - baseline-browser-mapping: 2.8.20 - caniuse-lite: 1.0.30001751 - electron-to-chromium: 1.5.240 - node-releases: 2.0.26 - update-browserslist-db: 1.1.4(browserslist@4.27.0) - - buffer-crc32@1.0.0: {} - - buffer@5.7.1: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - buffer@6.0.3: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - bytes@3.1.2: {} - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - - callsites@3.1.0: {} - - caniuse-lite@1.0.30001751: {} - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - character-entities-legacy@1.1.4: {} - - character-entities@1.2.4: {} - - character-reference-invalid@1.1.4: {} - - chardet@2.1.0: {} - - chokidar@4.0.3: - dependencies: - readdirp: 4.1.2 - - class-variance-authority@0.7.1: - dependencies: - clsx: 2.1.1 - - classcat@5.0.5: {} - - cli-cursor@3.1.0: - dependencies: - restore-cursor: 3.1.0 - - cli-spinners@2.9.2: {} - - cli-width@3.0.0: {} - - clone@1.0.4: {} - - clsx@2.1.1: {} - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - colors@1.4.0: {} - - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - - comma-separated-tokens@1.0.8: {} - - commander@13.1.0: {} - - compress-commons@6.0.2: - dependencies: - crc-32: 1.2.2 - crc32-stream: 6.0.0 - is-stream: 2.0.1 - normalize-path: 3.0.0 - readable-stream: 4.7.0 - - concat-map@0.0.1: {} - - content-disposition@0.5.4: - dependencies: - safe-buffer: 5.2.1 - - content-type@1.0.5: {} - - convert-source-map@2.0.0: {} - - cookie-signature@1.0.6: {} - - cookie@0.7.1: {} - - copy-to-clipboard@3.3.3: - dependencies: - toggle-selection: 1.0.6 - - core-util-is@1.0.3: {} - - crc-32@1.2.2: {} - - crc32-stream@6.0.0: - dependencies: - crc-32: 1.2.2 - readable-stream: 4.7.0 - - create-require@1.1.1: {} - - cron@4.3.3: - dependencies: - '@types/luxon': 3.7.1 - luxon: 3.7.2 - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - csstype@3.1.3: {} - - d3-color@3.1.0: {} - - d3-dispatch@3.0.1: {} - - d3-drag@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-selection: 3.0.0 - - d3-ease@3.0.1: {} - - d3-interpolate@3.0.1: - dependencies: - d3-color: 3.1.0 - - d3-selection@3.0.0: {} - - d3-timer@3.0.1: {} - - d3-transition@3.0.1(d3-selection@3.0.0): - dependencies: - d3-color: 3.1.0 - d3-dispatch: 3.0.1 - d3-ease: 3.0.1 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-timer: 3.0.1 - - d3-zoom@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-transition: 3.0.1(d3-selection@3.0.0) - - dagre@0.8.5: - dependencies: - graphlib: 2.1.8 - lodash: 4.17.21 - - date-fns@4.1.0: {} - - debug@2.6.9: - dependencies: - ms: 2.0.0 - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - deep-is@0.1.4: {} - - defaults@1.0.4: - dependencies: - clone: 1.0.4 - - delayed-stream@1.0.0: {} - - depd@2.0.0: {} - - destroy@1.2.0: {} - - detect-libc@2.1.2: {} - - detect-node-es@1.1.0: {} - - diff@4.0.2: {} - - dompurify@3.1.7: {} - - dotenv@16.6.1: {} - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - eastasianwidth@0.2.0: {} - - ee-first@1.1.1: {} - - electron-to-chromium@1.5.240: {} - - emoji-regex@8.0.0: {} - - emoji-regex@9.2.2: {} - - encodeurl@1.0.2: {} - - encodeurl@2.0.0: {} - - enhanced-resolve@5.18.3: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.0 - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - esbuild@0.25.11: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.11 - '@esbuild/android-arm': 0.25.11 - '@esbuild/android-arm64': 0.25.11 - '@esbuild/android-x64': 0.25.11 - '@esbuild/darwin-arm64': 0.25.11 - '@esbuild/darwin-x64': 0.25.11 - '@esbuild/freebsd-arm64': 0.25.11 - '@esbuild/freebsd-x64': 0.25.11 - '@esbuild/linux-arm': 0.25.11 - '@esbuild/linux-arm64': 0.25.11 - '@esbuild/linux-ia32': 0.25.11 - '@esbuild/linux-loong64': 0.25.11 - '@esbuild/linux-mips64el': 0.25.11 - '@esbuild/linux-ppc64': 0.25.11 - '@esbuild/linux-riscv64': 0.25.11 - '@esbuild/linux-s390x': 0.25.11 - '@esbuild/linux-x64': 0.25.11 - '@esbuild/netbsd-arm64': 0.25.11 - '@esbuild/netbsd-x64': 0.25.11 - '@esbuild/openbsd-arm64': 0.25.11 - '@esbuild/openbsd-x64': 0.25.11 - '@esbuild/openharmony-arm64': 0.25.11 - '@esbuild/sunos-x64': 0.25.11 - '@esbuild/win32-arm64': 0.25.11 - '@esbuild/win32-ia32': 0.25.11 - '@esbuild/win32-x64': 0.25.11 - - escalade@3.2.0: {} - - escape-html@1.0.3: {} - - escape-string-regexp@1.0.5: {} - - escape-string-regexp@4.0.0: {} - - eslint-scope@8.4.0: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@4.2.1: {} - - eslint@9.38.0(jiti@2.6.1): - dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@2.6.1)) - '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.1 - '@eslint/config-helpers': 0.4.1 - '@eslint/core': 0.16.0 - '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.38.0 - '@eslint/plugin-kit': 0.4.0 - '@humanfs/node': 0.16.7 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - optionalDependencies: - jiti: 2.6.1 - transitivePeerDependencies: - - supports-color - - espree@10.4.0: - dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 4.2.1 - - esquery@1.6.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@5.3.0: {} - - esutils@2.0.3: {} - - etag@1.8.1: {} - - event-target-shim@5.0.1: {} - - events-universal@1.0.1: - dependencies: - bare-events: 2.8.1 - transitivePeerDependencies: - - bare-abort-controller - - events@3.3.0: {} - - express@4.21.2: - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.3 - content-disposition: 0.5.4 - content-type: 1.0.5 - cookie: 0.7.1 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.3.1 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.3 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.12 - proxy-addr: 2.0.7 - qs: 6.13.0 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.19.0 - serve-static: 1.16.2 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - - fast-deep-equal@3.1.3: {} - - fast-fifo@1.3.2: {} - - fast-glob@3.3.3: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fast-uri@3.1.0: {} - - fastq@1.19.1: - dependencies: - reusify: 1.1.0 - - fault@1.0.4: - dependencies: - format: 0.2.2 - - fdir@6.5.0(picomatch@4.0.3): - optionalDependencies: - picomatch: 4.0.3 - - figures@3.2.0: - dependencies: - escape-string-regexp: 1.0.5 - - file-entry-cache@8.0.0: - dependencies: - flat-cache: 4.0.1 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - finalhandler@1.3.1: - dependencies: - debug: 2.6.9 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.1 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@4.0.1: - dependencies: - flatted: 3.3.3 - keyv: 4.5.4 - - flatted@3.3.3: {} - - follow-redirects@1.15.11: {} - - foreground-child@3.3.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - - form-data@4.0.4: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - - format@0.2.2: {} - - forwarded@0.2.0: {} - - fraction.js@4.3.7: {} - - fresh@0.5.2: {} - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - gensync@1.0.0-beta.2: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-nonce@1.0.1: {} - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - glob@10.4.5: - dependencies: - foreground-child: 3.3.1 - jackspeak: 3.4.3 - minimatch: 9.0.5 - minipass: 7.1.2 - package-json-from-dist: 1.0.1 - path-scurry: 1.11.1 - - glob@11.0.3: - dependencies: - foreground-child: 3.3.1 - jackspeak: 4.1.1 - minimatch: 10.0.3 - minipass: 7.1.2 - package-json-from-dist: 1.0.1 - path-scurry: 2.0.0 - - globals@14.0.0: {} - - gopd@1.2.0: {} - - graceful-fs@4.2.11: {} - - graphemer@1.4.0: {} - - graphlib@2.1.8: - dependencies: - lodash: 4.17.21 - - has-flag@4.0.0: {} - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - hast-util-parse-selector@2.2.5: {} - - hastscript@6.0.0: - dependencies: - '@types/hast': 2.3.10 - comma-separated-tokens: 1.0.8 - hast-util-parse-selector: 2.2.5 - property-information: 5.6.0 - space-separated-tokens: 1.1.5 - - highlight.js@10.7.3: {} - - highlightjs-vue@1.0.0: {} - - http-errors@2.0.0: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - - iconv-lite@0.4.24: - dependencies: - safer-buffer: 2.1.2 - - iconv-lite@0.7.0: - dependencies: - safer-buffer: 2.1.2 - - ieee754@1.2.1: {} - - ignore@5.3.2: {} - - ignore@7.0.5: {} - - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - imurmurhash@0.1.4: {} - - inherits@2.0.4: {} - - inquirer@8.2.7(@types/node@24.9.1): - dependencies: - '@inquirer/external-editor': 1.0.2(@types/node@24.9.1) - ansi-escapes: 4.3.2 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-width: 3.0.0 - figures: 3.2.0 - lodash: 4.17.21 - mute-stream: 0.0.8 - ora: 5.4.1 - run-async: 2.4.1 - rxjs: 7.8.2 - string-width: 4.2.3 - strip-ansi: 6.0.1 - through: 2.3.8 - wrap-ansi: 6.2.0 - transitivePeerDependencies: - - '@types/node' - - ipaddr.js@1.9.1: {} - - is-alphabetical@1.0.4: {} - - is-alphanumerical@1.0.4: - dependencies: - is-alphabetical: 1.0.4 - is-decimal: 1.0.4 - - is-decimal@1.0.4: {} - - is-extglob@2.1.1: {} - - is-fullwidth-code-point@3.0.0: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-hexadecimal@1.0.4: {} - - is-interactive@1.0.0: {} - - is-number@7.0.0: {} - - is-stream@2.0.1: {} - - is-unicode-supported@0.1.0: {} - - isarray@1.0.0: {} - - isexe@2.0.0: {} - - jackspeak@3.4.3: - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - - jackspeak@4.1.1: - dependencies: - '@isaacs/cliui': 8.0.2 - - jiti@2.6.1: {} - - js-tokens@4.0.0: {} - - js-yaml@4.1.0: - dependencies: - argparse: 2.0.1 - - jsesc@3.1.0: {} - - json-buffer@3.0.1: {} - - json-schema-traverse@0.4.1: {} - - json-schema-traverse@1.0.0: {} - - json-schema@0.4.0: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - json5@2.2.3: {} - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - lazystream@1.0.1: - dependencies: - readable-stream: 2.3.8 - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - - lightningcss-android-arm64@1.30.2: - optional: true - - lightningcss-darwin-arm64@1.30.2: - optional: true - - lightningcss-darwin-x64@1.30.2: - optional: true - - lightningcss-freebsd-x64@1.30.2: - optional: true - - lightningcss-linux-arm-gnueabihf@1.30.2: - optional: true - - lightningcss-linux-arm64-gnu@1.30.2: - optional: true - - lightningcss-linux-arm64-musl@1.30.2: - optional: true - - lightningcss-linux-x64-gnu@1.30.2: - optional: true - - lightningcss-linux-x64-musl@1.30.2: - optional: true - - lightningcss-win32-arm64-msvc@1.30.2: - optional: true - - lightningcss-win32-x64-msvc@1.30.2: - optional: true - - lightningcss@1.30.2: - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.30.2 - lightningcss-darwin-arm64: 1.30.2 - lightningcss-darwin-x64: 1.30.2 - lightningcss-freebsd-x64: 1.30.2 - lightningcss-linux-arm-gnueabihf: 1.30.2 - lightningcss-linux-arm64-gnu: 1.30.2 - lightningcss-linux-arm64-musl: 1.30.2 - lightningcss-linux-x64-gnu: 1.30.2 - lightningcss-linux-x64-musl: 1.30.2 - lightningcss-win32-arm64-msvc: 1.30.2 - lightningcss-win32-x64-msvc: 1.30.2 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lodash.merge@4.6.2: {} - - lodash.truncate@4.4.2: {} - - lodash@4.17.21: {} - - log-symbols@4.1.0: - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - - lowlight@1.20.0: - dependencies: - fault: 1.0.4 - highlight.js: 10.7.3 - - lru-cache@10.4.3: {} - - lru-cache@11.2.2: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - lucide-react@0.510.0(react@19.2.0): - dependencies: - react: 19.2.0 - - lucide-react@0.525.0(react@19.2.0): - dependencies: - react: 19.2.0 - - lucide-react@0.544.0(react@19.2.0): - dependencies: - react: 19.2.0 - - luxon@3.7.2: {} - - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - make-error@1.3.6: {} - - marked@14.0.0: {} - - math-intrinsics@1.1.0: {} - - media-typer@0.3.0: {} - - merge-descriptors@1.0.3: {} - - merge2@1.4.1: {} - - methods@1.1.2: {} - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - mime@1.6.0: {} - - mimic-fn@2.1.0: {} - - minimatch@10.0.3: - dependencies: - '@isaacs/brace-expansion': 5.0.0 - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.12 - - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.2 - - minimatch@9.0.5: - dependencies: - brace-expansion: 2.0.2 - - minimist@1.2.8: {} - - minipass@7.1.2: {} - - monaco-editor@0.54.0: - dependencies: - dompurify: 3.1.7 - marked: 14.0.0 - - motia@0.8.2-beta.139(@types/node@24.9.1)(@types/react@18.3.26)(eslint@9.38.0(jiti@2.6.1))(jiti@2.6.1)(lightningcss@1.30.2)(monaco-editor@0.54.0)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@19.2.0)): - dependencies: - '@amplitude/analytics-node': 1.5.20 - '@motiadev/core': 0.8.2-beta.139(@types/node@24.9.1)(typescript@5.9.3) - '@motiadev/stream-client-node': 0.8.2-beta.139 - '@motiadev/workbench': 0.8.2-beta.139(@types/node@24.9.1)(@types/react@18.3.26)(eslint@9.38.0(jiti@2.6.1))(jiti@2.6.1)(lightningcss@1.30.2)(monaco-editor@0.54.0)(use-sync-external-store@1.6.0(react@19.2.0)) - antlr4ts: 0.5.0-alpha.4 - archiver: 7.0.1 - axios: 1.12.2 - chokidar: 4.0.3 - colors: 1.4.0 - commander: 13.1.0 - cron: 4.3.3 - dotenv: 16.6.1 - esbuild: 0.25.11 - express: 4.21.2 - glob: 11.0.3 - inquirer: 8.2.7(@types/node@24.9.1) - node-cron: 3.0.3 - python-ast: 0.1.0 - table: 6.9.0 - ts-node: 10.9.2(@types/node@24.9.1)(typescript@5.9.3) - transitivePeerDependencies: - - '@swc/core' - - '@swc/wasm' - - '@types/node' - - '@types/react' - - '@types/react-dom' - - bare-abort-controller - - bufferutil - - debug - - eslint - - immer - - jiti - - less - - lightningcss - - monaco-editor - - react-native-b4a - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - typescript - - use-sync-external-store - - utf-8-validate - - yaml - - ms@2.0.0: {} - - ms@2.1.3: {} - - mute-stream@0.0.8: {} - - nanoid@3.3.11: {} - - natural-compare@1.4.0: {} - - negotiator@0.6.3: {} - - node-cron@3.0.3: - dependencies: - uuid: 8.3.2 - - node-releases@2.0.26: {} - - normalize-path@3.0.0: {} - - normalize-range@0.1.2: {} - - object-inspect@1.13.4: {} - - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - - onetime@5.1.2: - dependencies: - mimic-fn: 2.1.0 - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - ora@5.4.1: - dependencies: - bl: 4.1.0 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-spinners: 2.9.2 - is-interactive: 1.0.0 - is-unicode-supported: 0.1.0 - log-symbols: 4.1.0 - strip-ansi: 6.0.1 - wcwidth: 1.0.1 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - package-json-from-dist@1.0.1: {} - - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - parse-entities@2.0.0: - dependencies: - character-entities: 1.2.4 - character-entities-legacy: 1.1.4 - character-reference-invalid: 1.1.4 - is-alphanumerical: 1.0.4 - is-decimal: 1.0.4 - is-hexadecimal: 1.0.4 - - parseurl@1.3.3: {} - - path-exists@4.0.0: {} - - path-key@3.1.1: {} - - path-scurry@1.11.1: - dependencies: - lru-cache: 10.4.3 - minipass: 7.1.2 - - path-scurry@2.0.0: - dependencies: - lru-cache: 11.2.2 - minipass: 7.1.2 - - path-to-regexp@0.1.12: {} - - picocolors@1.1.1: {} - - picomatch@2.3.1: {} - - picomatch@4.0.3: {} - - postcss-value-parser@4.2.0: {} - - postcss@8.5.6: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - prelude-ls@1.2.1: {} - - prismjs@1.27.0: {} - - prismjs@1.30.0: {} - - process-nextick-args@2.0.1: {} - - process@0.11.10: {} - - property-information@5.6.0: - dependencies: - xtend: 4.0.2 - - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - - proxy-from-env@1.1.0: {} - - punycode@2.3.1: {} - - python-ast@0.1.0: - dependencies: - antlr4ts: 0.5.0-alpha.4 - - qs@6.13.0: - dependencies: - side-channel: 1.1.0 - - queue-microtask@1.2.3: {} - - range-parser@1.2.1: {} - - raw-body@2.5.2: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - - react-dom@19.2.0(react@19.2.0): - dependencies: - react: 19.2.0 - scheduler: 0.27.0 - - react-refresh@0.17.0: {} - - react-remove-scroll-bar@2.3.8(@types/react@18.3.26)(react@19.2.0): - dependencies: - react: 19.2.0 - react-style-singleton: 2.2.3(@types/react@18.3.26)(react@19.2.0) - tslib: 2.8.1 - optionalDependencies: - '@types/react': 18.3.26 - - react-remove-scroll@2.7.1(@types/react@18.3.26)(react@19.2.0): - dependencies: - react: 19.2.0 - react-remove-scroll-bar: 2.3.8(@types/react@18.3.26)(react@19.2.0) - react-style-singleton: 2.2.3(@types/react@18.3.26)(react@19.2.0) - tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@18.3.26)(react@19.2.0) - use-sidecar: 1.1.3(@types/react@18.3.26)(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - - react-resizable-panels@3.0.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0): - dependencies: - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - - react-style-singleton@2.2.3(@types/react@18.3.26)(react@19.2.0): - dependencies: - get-nonce: 1.0.1 - react: 19.2.0 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 18.3.26 - - react-syntax-highlighter@15.6.6(react@19.2.0): - dependencies: - '@babel/runtime': 7.28.4 - highlight.js: 10.7.3 - highlightjs-vue: 1.0.0 - lowlight: 1.20.0 - prismjs: 1.30.0 - react: 19.2.0 - refractor: 3.6.0 - - react-use-resizable@0.2.0(react@19.2.0): - dependencies: - react: 19.2.0 - - react18-json-view@0.2.9(react@19.2.0): - dependencies: - copy-to-clipboard: 3.3.3 - react: 19.2.0 - - react@19.2.0: {} - - readable-stream@2.3.8: - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 - - readable-stream@3.6.2: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - - readable-stream@4.7.0: - dependencies: - abort-controller: 3.0.0 - buffer: 6.0.3 - events: 3.3.0 - process: 0.11.10 - string_decoder: 1.3.0 - - readdir-glob@1.1.3: - dependencies: - minimatch: 5.1.6 - - readdirp@4.1.2: {} - - refractor@3.6.0: - dependencies: - hastscript: 6.0.0 - parse-entities: 2.0.0 - prismjs: 1.27.0 - - require-from-string@2.0.2: {} - - resolve-from@4.0.0: {} - - restore-cursor@3.1.0: - dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 - - reusify@1.1.0: {} - - rollup@4.52.5: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.52.5 - '@rollup/rollup-android-arm64': 4.52.5 - '@rollup/rollup-darwin-arm64': 4.52.5 - '@rollup/rollup-darwin-x64': 4.52.5 - '@rollup/rollup-freebsd-arm64': 4.52.5 - '@rollup/rollup-freebsd-x64': 4.52.5 - '@rollup/rollup-linux-arm-gnueabihf': 4.52.5 - '@rollup/rollup-linux-arm-musleabihf': 4.52.5 - '@rollup/rollup-linux-arm64-gnu': 4.52.5 - '@rollup/rollup-linux-arm64-musl': 4.52.5 - '@rollup/rollup-linux-loong64-gnu': 4.52.5 - '@rollup/rollup-linux-ppc64-gnu': 4.52.5 - '@rollup/rollup-linux-riscv64-gnu': 4.52.5 - '@rollup/rollup-linux-riscv64-musl': 4.52.5 - '@rollup/rollup-linux-s390x-gnu': 4.52.5 - '@rollup/rollup-linux-x64-gnu': 4.52.5 - '@rollup/rollup-linux-x64-musl': 4.52.5 - '@rollup/rollup-openharmony-arm64': 4.52.5 - '@rollup/rollup-win32-arm64-msvc': 4.52.5 - '@rollup/rollup-win32-ia32-msvc': 4.52.5 - '@rollup/rollup-win32-x64-gnu': 4.52.5 - '@rollup/rollup-win32-x64-msvc': 4.52.5 - fsevents: 2.3.3 - - run-async@2.4.1: {} - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - - rxjs@7.8.2: - dependencies: - tslib: 2.8.1 - - safe-buffer@5.1.2: {} - - safe-buffer@5.2.1: {} - - safer-buffer@2.1.2: {} - - scheduler@0.27.0: {} - - semver@6.3.1: {} - - semver@7.7.3: {} - - send@0.19.0: - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - - serve-static@1.16.2: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.19.0 - transitivePeerDependencies: - - supports-color - - setprototypeof@1.2.0: {} - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - side-channel-list@1.0.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.0 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - - signal-exit@3.0.7: {} - - signal-exit@4.1.0: {} - - slice-ansi@4.0.0: - dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 - - source-map-js@1.2.1: {} - - space-separated-tokens@1.1.5: {} - - state-local@1.0.7: {} - - statuses@2.0.1: {} - - streamx@2.23.0: - dependencies: - events-universal: 1.0.1 - fast-fifo: 1.3.2 - text-decoder: 1.2.3 - transitivePeerDependencies: - - bare-abort-controller - - react-native-b4a - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.2 - - string_decoder@1.1.1: - dependencies: - safe-buffer: 5.1.2 - - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-ansi@7.1.2: - dependencies: - ansi-regex: 6.2.2 - - strip-bom@3.0.0: {} - - strip-json-comments@3.1.1: {} - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - table@6.9.0: - dependencies: - ajv: 8.17.1 - lodash.truncate: 4.4.2 - slice-ansi: 4.0.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - tailwind-merge@3.3.1: {} - - tailwindcss@4.1.16: {} - - tapable@2.3.0: {} - - tar-stream@3.1.7: - dependencies: - b4a: 1.7.3 - fast-fifo: 1.3.2 - streamx: 2.23.0 - transitivePeerDependencies: - - bare-abort-controller - - react-native-b4a - - text-decoder@1.2.3: - dependencies: - b4a: 1.7.3 - transitivePeerDependencies: - - react-native-b4a - - through@2.3.8: {} - - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - toggle-selection@1.0.6: {} - - toidentifier@1.0.1: {} - - ts-api-utils@2.1.0(typescript@5.8.3): - dependencies: - typescript: 5.8.3 - - ts-node@10.9.2(@types/node@24.9.1)(typescript@5.9.3): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 24.9.1 - acorn: 8.15.0 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.9.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - - tsconfig-paths@4.2.0: - dependencies: - json5: 2.2.3 - minimist: 1.2.8 - strip-bom: 3.0.0 - - tslib@2.8.1: {} - - tw-animate-css@1.4.0: {} - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - type-fest@0.21.3: {} - - type-is@1.6.18: - dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 - - typescript-eslint@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3) - '@typescript-eslint/parser': 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.8.3) - '@typescript-eslint/utils': 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3) - eslint: 9.38.0(jiti@2.6.1) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - - typescript@5.8.3: {} - - typescript@5.9.3: {} - - undici-types@7.16.0: {} - - unpipe@1.0.0: {} - - update-browserslist-db@1.1.4(browserslist@4.27.0): - dependencies: - browserslist: 4.27.0 - escalade: 3.2.0 - picocolors: 1.1.1 - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - use-callback-ref@1.3.3(@types/react@18.3.26)(react@19.2.0): - dependencies: - react: 19.2.0 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 18.3.26 - - use-sidecar@1.1.3(@types/react@18.3.26)(react@19.2.0): - dependencies: - detect-node-es: 1.1.0 - react: 19.2.0 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 18.3.26 - - use-sync-external-store@1.6.0(react@19.2.0): - dependencies: - react: 19.2.0 - - util-deprecate@1.0.2: {} - - utils-merge@1.0.1: {} - - uuid@11.1.0: {} - - uuid@8.3.2: {} - - v8-compile-cache-lib@3.0.1: {} - - vary@1.1.2: {} - - vite@6.4.1(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.30.2): - dependencies: - esbuild: 0.25.11 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.52.5 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 24.9.1 - fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.2 - - wcwidth@1.0.1: - dependencies: - defaults: 1.0.4 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - word-wrap@1.2.5: {} - - wrap-ansi@6.2.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrap-ansi@7.0.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrap-ansi@8.1.0: - dependencies: - ansi-styles: 6.2.3 - string-width: 5.1.2 - strip-ansi: 7.1.2 - - ws@8.18.3: {} - - xtend@4.0.2: {} - - yallist@3.1.1: {} - - yn@3.1.1: {} - - yocto-queue@0.1.0: {} - - zip-stream@6.0.1: - dependencies: - archiver-utils: 5.0.2 - compress-commons: 6.0.2 - readable-stream: 4.7.0 - - zod-to-json-schema@3.24.6(zod@3.25.76): - dependencies: - zod: 3.25.76 - - zod@3.25.76: {} - - zustand@4.5.7(@types/react@18.3.26)(react@19.2.0): - dependencies: - use-sync-external-store: 1.6.0(react@19.2.0) - optionalDependencies: - '@types/react': 18.3.26 - react: 19.2.0 - - zustand@5.0.8(@types/react@18.3.26)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)): - optionalDependencies: - '@types/react': 18.3.26 - react: 19.2.0 - use-sync-external-store: 1.6.0(react@19.2.0) diff --git a/motia/steps/async-image-upload.step.ts b/motia/steps/async-image-upload.step.ts deleted file mode 100644 index 13cbaa7..0000000 --- a/motia/steps/async-image-upload.step.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { ApiRouteConfig, Handlers } from 'motia'; -import { z } from 'zod'; - -const bodySchema = z.object({ - image: z.string().min(1, 'Image data is required'), - originalName: z.string().optional(), - pageId: z.string().optional(), - userId: z.string().min(1, 'User ID is required'), -}); - -export const config: ApiRouteConfig = { - type: 'api', - name: 'AsyncImageUpload', - path: '/images/upload', - method: 'POST', - emits: ['process-image-upload'], - flows: ['image-management'], - bodySchema, - responseSchema: { - 202: z.object({ - message: z.string(), - jobId: z.string(), - }), - 400: z.object({ - error: z.string(), - }), - }, -}; - -export const handler: Handlers['AsyncImageUpload'] = async (req, { emit, logger }) => { - try { - const { image, originalName, pageId, userId } = bodySchema.parse(req.body); - - const jobId = `image-upload-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; - logger.info('Starting async image upload', { jobId, userId, pageId: pageId || 'none' }); - - await emit({ - topic: 'process-image-upload', - data: { - jobId, - image, - originalName, - pageId, - userId, - }, - }); - - return { - status: 202, // Accepted - processing asynchronously - body: { - message: 'Image upload job queued for processing', - jobId, - }, - }; - } catch (error) { - logger.error('Failed to queue image upload', { error: (error as Error).message }); - return { - status: 400, - body: { error: 'Invalid request data' }, - }; - } -}; diff --git a/motia/steps/async-page-save.step.ts b/motia/steps/async-page-save.step.ts deleted file mode 100644 index d340704..0000000 --- a/motia/steps/async-page-save.step.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { ApiRouteConfig, Handlers } from 'motia'; -import { z } from 'zod'; - -const bodySchema = z.object({ - pageId: z.string().min(1, 'Page ID is required'), - newPageData: z.string().min(0, 'Page data is required'), - userId: z.string().min(1, 'User ID is required'), -}); - -export const config: ApiRouteConfig = { - type: 'api', - name: 'AsyncPageSave', - path: '/pages/save', - method: 'POST', - emits: ['process-page-save'], - flows: ['page-management'], - bodySchema, - responseSchema: { - 202: z.object({ - message: z.string(), - jobId: z.string(), - pageId: z.string(), - }), - 400: z.object({ - error: z.string(), - }), - }, -}; - -export const handler: Handlers['AsyncPageSave'] = async (req, { emit, logger }) => { - try { - const { pageId, newPageData, userId } = bodySchema.parse(req.body); - - const jobId = `page-save-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; - logger.info('Starting async page save', { jobId, pageId, userId }); - - await emit({ - topic: 'process-page-save', - data: { - jobId, - pageId, - newPageData, - userId, - }, - }); - - return { - status: 202, // Accepted - processing asynchronously - body: { - message: 'Page save job queued for processing', - jobId, - pageId, - }, - }; - } catch (error) { - logger.error('Failed to queue page save', { error: (error as Error).message }); - return { - status: 400, - body: { error: 'Invalid request data' }, - }; - } -}; diff --git a/motia/steps/cleanup-marked-images.step.ts b/motia/steps/cleanup-marked-images.step.ts deleted file mode 100644 index 48d72f8..0000000 --- a/motia/steps/cleanup-marked-images.step.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { EventConfig, Handlers } from 'motia'; -import { z } from 'zod'; -import axios from 'axios'; - -const inputSchema = z.object({ - jobId: z.string(), - batchSize: z.number().min(1).max(100), - cleanupType: z.string(), -}); - -export const config: EventConfig = { - type: 'event', - name: 'CleanupMarkedImages', - description: 'Deletes images from Cloudinary that are marked for deletion', - subscribes: ['cleanup-marked-images'], - emits: [], - input: inputSchema, - flows: ['image-management'], -}; - -export const handler: Handlers['CleanupMarkedImages'] = async (input, { logger, state }) => { - const { jobId, batchSize, cleanupType } = input; - - try { - logger.info('Starting cleanup of marked images', { jobId, batchSize, cleanupType }); - - // Call backend API to get and cleanup marked images - const backendUrl = process.env.BACKEND_URL || 'http://localhost:3000'; - - const response = await axios.post( - `${backendUrl}/api/cleanup/marked-images`, - { - batchSize, - jobId, - }, - { - headers: { - 'Content-Type': 'application/json', - // Add any authentication headers if needed - }, - timeout: 300000, // 5 minutes timeout for heavy operations - } - ); - - const result = response.data; - - logger.info('Marked images cleanup completed', { - jobId, - deletedCount: result.deletedCount, - failedCount: result.failedCount, - totalProcessed: result.totalProcessed, - }); - - // Store cleanup results in state for monitoring - await state.set('cleanup-jobs', jobId, { - type: 'marked-images', - status: 'completed', - result, - completedAt: new Date().toISOString(), - }); - } catch (error) { - logger.error('Failed to cleanup marked images', { - jobId, - error: (error as Error).message, - stack: (error as Error).stack, - }); - - // Store failure in state - await state.set('cleanup-jobs', jobId, { - type: 'marked-images', - status: 'failed', - error: (error as Error).message, - failedAt: new Date().toISOString(), - }); - - throw error; // Re-throw to let Motia handle retry logic if configured - } -}; diff --git a/motia/steps/cleanup-orphaned-images.step.ts b/motia/steps/cleanup-orphaned-images.step.ts deleted file mode 100644 index b0b7bd3..0000000 --- a/motia/steps/cleanup-orphaned-images.step.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { EventConfig, Handlers } from 'motia'; -import { z } from 'zod'; -import axios from 'axios'; - -const inputSchema = z.object({ - jobId: z.string(), - cleanupType: z.string(), -}); - -export const config: EventConfig = { - type: 'event', - name: 'CleanupOrphanedImages', - description: 'Finds and marks orphaned images for deletion', - subscribes: ['cleanup-orphaned-images'], - emits: [], - input: inputSchema, - flows: ['image-management'], -}; - -export const handler: Handlers['CleanupOrphanedImages'] = async (input, { logger, state }) => { - const { jobId, cleanupType } = input; - - try { - logger.info('Starting orphaned images detection', { jobId, cleanupType }); - - // Call backend API to mark orphaned images - const backendUrl = process.env.BACKEND_URL || 'http://localhost:4000'; - - const response = await axios.post( - `${backendUrl}/api/cleanup/orphaned-images`, - { - jobId, - }, - { - headers: { - 'Content-Type': 'application/json', - }, - timeout: 300000, // 5 minutes timeout - } - ); - - const result = response.data; - - logger.info('Orphaned images detection completed', { - jobId, - markedCount: result.markedCount, - }); - - // Store cleanup results in state for monitoring - await state.set('cleanup-jobs', jobId, { - type: 'orphaned-images', - status: 'completed', - result, - completedAt: new Date().toISOString(), - }); - } catch (error) { - logger.error('Failed to detect orphaned images', { - jobId, - error: (error as Error).message, - stack: (error as Error).stack, - }); - - // Store failure in state - await state.set('cleanup-jobs', jobId, { - type: 'orphaned-images', - status: 'failed', - error: (error as Error).message, - failedAt: new Date().toISOString(), - }); - - throw error; - } -}; diff --git a/motia/steps/health-check.step.ts b/motia/steps/health-check.step.ts deleted file mode 100644 index 0a4f161..0000000 --- a/motia/steps/health-check.step.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { ApiRouteConfig, Handlers } from 'motia'; -import { z } from 'zod'; - -export const config: ApiRouteConfig = { - type: 'api', - name: 'HealthCheck', - path: '/health', - method: 'GET', - emits: [], - flows: ['system'], - responseSchema: { - 200: z.object({ - status: z.string(), - timestamp: z.string(), - service: z.string(), - }), - }, -}; - -export const handler: Handlers['HealthCheck'] = async () => { - return { - status: 200, - body: { - status: 'healthy', - timestamp: new Date().toISOString(), - service: 'motia', - }, - }; -}; diff --git a/motia/steps/process-image-upload.step.ts b/motia/steps/process-image-upload.step.ts deleted file mode 100644 index 6f8957f..0000000 --- a/motia/steps/process-image-upload.step.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { EventConfig, Handlers } from 'motia'; -import { z } from 'zod'; -import axios from 'axios'; - -const inputSchema = z.object({ - jobId: z.string(), - image: z.string(), - originalName: z.string().optional(), - pageId: z.string().optional(), - userId: z.string(), -}); - -export const config: EventConfig = { - type: 'event', - name: 'ProcessImageUpload', - description: 'Processes image upload to Cloudinary and saves metadata to database', - subscribes: ['process-image-upload'], - emits: [], - input: inputSchema, - flows: ['image-management'], -}; - -export const handler: Handlers['ProcessImageUpload'] = async (input, { logger, state }) => { - const { jobId, image, originalName, pageId, userId } = input; - - try { - logger.info('Processing image upload', { jobId, userId, pageId: pageId || 'none' }); - - // Call backend API to perform the actual image upload - const backendUrl = process.env.BACKEND_URL || 'http://localhost:3000'; - - const response = await axios.post( - `${backendUrl}/api/images/upload-async`, - { - jobId, - image, - originalName, - pageId, - userId, - }, - { - headers: { - 'Content-Type': 'application/json', - }, - timeout: 120000, // 2 minutes timeout for image uploads - } - ); - - const result = response.data; - - logger.info('Image upload completed successfully', { - jobId, - userId, - imageId: result.imageId, - imageUrl: result.imageUrl, - }); - - // Store upload results in state for monitoring - await state.set('image-upload-jobs', jobId, { - type: 'image-upload', - status: 'completed', - result, - userId, - pageId, - completedAt: new Date().toISOString(), - }); - } catch (error) { - logger.error('Failed to process image upload', { - jobId, - userId, - pageId, - error: (error as Error).message, - stack: (error as Error).stack, - }); - - // Store failure in state - await state.set('image-upload-jobs', jobId, { - type: 'image-upload', - status: 'failed', - error: (error as Error).message, - userId, - pageId, - failedAt: new Date().toISOString(), - }); - - throw error; - } -}; diff --git a/motia/steps/process-page-save.step.ts b/motia/steps/process-page-save.step.ts deleted file mode 100644 index bab163a..0000000 --- a/motia/steps/process-page-save.step.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { EventConfig, Handlers } from 'motia'; -import { z } from 'zod'; -import axios from 'axios'; - -const inputSchema = z.object({ - jobId: z.string(), - pageId: z.string(), - newPageData: z.string(), - userId: z.string(), -}); - -export const config: EventConfig = { - type: 'event', - name: 'ProcessPageSave', - description: - 'Processes page save operations including image reference updates and cache management', - subscribes: ['process-page-save'], - emits: [], - input: inputSchema, - flows: ['page-management'], -}; - -export const handler: Handlers['ProcessPageSave'] = async (input, { logger, state }) => { - const { jobId, pageId, newPageData, userId } = input; - - try { - logger.info('Processing page save', { jobId, pageId, userId }); - - // Call backend API to perform the actual page save - const backendUrl = process.env.BACKEND_URL || 'http://localhost:4000'; - const response = await axios.post( - `${backendUrl}/api/v2/pages/process-async-save`, - { - jobId, - pageId, - newPageData, - userId, - }, - { - headers: { - 'Content-Type': 'application/json', - }, - timeout: 60000, // 1 minute timeout for page operations - } - ); - - const result = response.data; - - logger.info('Page save completed successfully', { - jobId, - pageId, - userId, - updated: result.updated, - }); - - // Store save results in state for monitoring - await state.set('page-save-jobs', jobId, { - type: 'page-save', - status: 'completed', - result, - pageId, - userId, - completedAt: new Date().toISOString(), - }); - } catch (error) { - logger.error('Failed to process page save', { - jobId, - pageId, - userId, - error: (error as Error).message, - stack: (error as Error).stack, - }); - - // Store failure in state - await state.set('page-save-jobs', jobId, { - type: 'page-save', - status: 'failed', - error: (error as Error).message, - pageId, - userId, - failedAt: new Date().toISOString(), - }); - - throw error; - } -}; diff --git a/motia/steps/scheduled-image-cleanup.step.ts b/motia/steps/scheduled-image-cleanup.step.ts deleted file mode 100644 index 3690b43..0000000 --- a/motia/steps/scheduled-image-cleanup.step.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { CronConfig, Handlers } from 'motia'; - -export const config: CronConfig = { - type: 'cron', - name: 'ScheduledImageCleanup', - description: 'Scheduled comprehensive image cleanup every 6 hours', - cron: '0 */6 * * *', // Every 6 hours - emits: ['cleanup-marked-images', 'cleanup-orphaned-images'], - flows: ['image-management'], -}; - -export const handler: Handlers['ScheduledImageCleanup'] = async ({ emit, logger }) => { - const jobId = `scheduled-cleanup-${Date.now()}`; - - logger.info('Starting scheduled comprehensive image cleanup', { jobId }); - - try { - // Trigger comprehensive cleanup (both marked and orphaned) - await emit({ - topic: 'cleanup-marked-images', - data: { - jobId: `${jobId}-marked`, - batchSize: 50, - cleanupType: 'comprehensive', - }, - }); - - await emit({ - topic: 'cleanup-orphaned-images', - data: { - jobId: `${jobId}-orphaned`, - cleanupType: 'comprehensive', - }, - }); - - logger.info('Scheduled image cleanup jobs triggered successfully', { jobId }); - } catch (error) { - logger.error('Failed to trigger scheduled image cleanup', { - jobId, - error: (error as Error).message, - }); - throw error; - } -}; diff --git a/motia/steps/scheduled-task-reminders.step.ts b/motia/steps/scheduled-task-reminders.step.ts deleted file mode 100644 index b32906c..0000000 --- a/motia/steps/scheduled-task-reminders.step.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { CronConfig, Handlers } from 'motia'; - -export const config: CronConfig = { - type: 'cron', - name: 'ScheduledTaskReminders', - description: 'Scheduled task reminder check every 5 minutes', - cron: '*/5 * * * *', // Every 5 minutes - emits: ['send-task-reminders'], - flows: ['task-management'], -}; - -export const handler: Handlers['ScheduledTaskReminders'] = async ({ emit, logger }) => { - const jobId = `scheduled-reminder-${Date.now()}`; - - logger.info('Starting scheduled task reminder check', { jobId }); - - try { - await emit({ - topic: 'send-task-reminders', - data: { - jobId, - checkType: 'all', - }, - }); - - logger.info('Scheduled task reminder check triggered successfully', { jobId }); - } catch (error) { - logger.error('Failed to trigger scheduled task reminders', { - jobId, - error: (error as Error).message, - }); - throw error; - } -}; diff --git a/motia/steps/send-task-reminders.step.ts b/motia/steps/send-task-reminders.step.ts deleted file mode 100644 index b53ddcf..0000000 --- a/motia/steps/send-task-reminders.step.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { EventConfig, Handlers } from 'motia'; -import { z } from 'zod'; -import axios from 'axios'; - -const inputSchema = z.object({ - jobId: z.string(), - checkType: z.string(), -}); - -export const config: EventConfig = { - type: 'event', - name: 'SendTaskReminders', - description: 'Checks for tasks nearing deadline and sends reminder emails', - subscribes: ['send-task-reminders'], - emits: [], - input: inputSchema, - flows: ['task-management'], -}; - -export const handler: Handlers['SendTaskReminders'] = async (input, { logger, state }) => { - const { jobId, checkType } = input; - - try { - logger.info('Starting task reminder check', { jobId, checkType }); - - // Call backend API to check and send reminders - const backendUrl = process.env.BACKEND_URL || 'http://localhost:4000'; - - const response = await axios.post( - `${backendUrl}/api/reminders/check`, - { - jobId, - checkType, - }, - { - headers: { - 'Content-Type': 'application/json', - }, - timeout: 120000, // 2 minutes timeout - } - ); - - const result = response.data; - - logger.info('Task reminder check completed', { - jobId, - oneHourReminders: result.oneHourReminders || 0, - overdueReminders: result.overdueReminders || 0, - }); - - // Store reminder results in state for monitoring - await state.set('reminder-jobs', jobId, { - type: 'task-reminders', - status: 'completed', - result, - completedAt: new Date().toISOString(), - }); - } catch (error) { - logger.error('Failed to send task reminders', { - jobId, - error: (error as Error).message, - stack: (error as Error).stack, - }); - - // Store failure in state - await state.set('reminder-jobs', jobId, { - type: 'task-reminders', - status: 'failed', - error: (error as Error).message, - failedAt: new Date().toISOString(), - }); - - throw error; - } -}; diff --git a/motia/steps/trigger-image-cleanup.step.ts b/motia/steps/trigger-image-cleanup.step.ts deleted file mode 100644 index 762d0ae..0000000 --- a/motia/steps/trigger-image-cleanup.step.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { ApiRouteConfig, Handlers } from 'motia'; -import { z } from 'zod'; - -const bodySchema = z.object({ - cleanupType: z.enum(['marked', 'orphaned', 'comprehensive']).optional().default('comprehensive'), - batchSize: z.number().min(1).max(100).optional().default(50), -}); - -export const config: ApiRouteConfig = { - type: 'api', - name: 'TriggerImageCleanup', - path: '/cleanup/images', - method: 'POST', - emits: ['cleanup-marked-images', 'cleanup-orphaned-images'], - flows: ['image-management'], - bodySchema, - responseSchema: { - 200: z.object({ - message: z.string(), - cleanupType: z.string(), - jobId: z.string(), - }), - 400: z.object({ - error: z.string(), - }), - }, -}; - -export const handler: Handlers['TriggerImageCleanup'] = async (req, { emit, logger }) => { - try { - const { cleanupType, batchSize } = bodySchema.parse(req.body); - - const jobId = `cleanup-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; - logger.info('Starting image cleanup job', { jobId, cleanupType, batchSize }); - - if (cleanupType === 'marked' || cleanupType === 'comprehensive') { - await emit({ - topic: 'cleanup-marked-images', - data: { - jobId, - batchSize, - cleanupType, - }, - }); - } - - if (cleanupType === 'orphaned' || cleanupType === 'comprehensive') { - await emit({ - topic: 'cleanup-orphaned-images', - data: { - jobId, - cleanupType, - }, - }); - } - - return { - status: 200, - body: { - message: `Image cleanup job started: ${cleanupType}`, - cleanupType, - jobId, - }, - }; - } catch (error) { - logger.error('Failed to trigger image cleanup', { error: (error as Error).message }); - return { - status: 400, - body: { error: 'Invalid request data' }, - }; - } -}; diff --git a/motia/steps/trigger-task-reminders.step.ts b/motia/steps/trigger-task-reminders.step.ts deleted file mode 100644 index 76bcb03..0000000 --- a/motia/steps/trigger-task-reminders.step.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { ApiRouteConfig, Handlers } from 'motia'; -import { z } from 'zod'; - -const bodySchema = z.object({ - checkType: z.enum(['all', 'one-hour', 'overdue']).optional().default('all'), -}); - -export const config: ApiRouteConfig = { - type: 'api', - name: 'TriggerTaskReminders', - path: '/reminders/tasks', - method: 'POST', - emits: ['send-task-reminders'], - flows: ['task-management'], - bodySchema, - responseSchema: { - 200: z.object({ - message: z.string(), - checkType: z.string(), - jobId: z.string(), - }), - 400: z.object({ - error: z.string(), - }), - }, -}; - -export const handler: Handlers['TriggerTaskReminders'] = async (req, { emit, logger }) => { - try { - const { checkType } = bodySchema.parse(req.body); - - const jobId = `reminder-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; - logger.info('Starting task reminder check', { jobId, checkType }); - - await emit({ - topic: 'send-task-reminders', - data: { - jobId, - checkType, - }, - }); - - return { - status: 200, - body: { - message: `Task reminder check started: ${checkType}`, - checkType, - jobId, - }, - }; - } catch (error) { - logger.error('Failed to trigger task reminders', { error: (error as Error).message }); - return { - status: 400, - body: { error: 'Invalid request data' }, - }; - } -}; diff --git a/motia/tsconfig.json b/motia/tsconfig.json deleted file mode 100644 index acf70cf..0000000 --- a/motia/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ESNext", - "moduleResolution": "Node", - "esModuleInterop": true, - "strict": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "allowJs": true, - "outDir": "dist", - "rootDir": ".", - "baseUrl": ".", - "jsx": "react-jsx" - }, - "include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "types.d.ts"], - "exclude": ["node_modules", "dist", "tests"] -} diff --git a/motia/types.d.ts b/motia/types.d.ts deleted file mode 100644 index aceac6e..0000000 --- a/motia/types.d.ts +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Automatically generated types for motia - * Do NOT edit this file manually. - * - * Consider adding this file to .prettierignore and eslint ignore. - */ -import { EventHandler, ApiRouteHandler, ApiResponse, MotiaStream, CronHandler } from 'motia'; - -declare module 'motia' { - interface FlowContextStateStreams {} - - interface Handlers { - TriggerTaskReminders: ApiRouteHandler< - { checkType?: 'all' | 'one-hour' | 'overdue' }, - | ApiResponse<200, { message: string; checkType: string; jobId: string }> - | ApiResponse<400, { error: string }>, - { topic: 'send-task-reminders'; data: { jobId: string; checkType: string } } - >; - TriggerImageCleanup: ApiRouteHandler< - { cleanupType?: 'marked' | 'orphaned' | 'comprehensive'; batchSize?: number }, - | ApiResponse<200, { message: string; cleanupType: string; jobId: string }> - | ApiResponse<400, { error: string }>, - | { - topic: 'cleanup-marked-images'; - data: { jobId: string; batchSize: number; cleanupType: string }; - } - | { topic: 'cleanup-orphaned-images'; data: { jobId: string; cleanupType: string } } - >; - SendTaskReminders: EventHandler<{ jobId: string; checkType: string }, never>; - ScheduledTaskReminders: CronHandler<{ - topic: 'send-task-reminders'; - data: { jobId: string; checkType: string }; - }>; - ScheduledImageCleanup: CronHandler< - | { - topic: 'cleanup-marked-images'; - data: { jobId: string; batchSize: number; cleanupType: string }; - } - | { topic: 'cleanup-orphaned-images'; data: { jobId: string; cleanupType: string } } - >; - ProcessPageSave: EventHandler< - { jobId: string; pageId: string; newPageData: string; userId: string }, - never - >; - ProcessImageUpload: EventHandler< - { jobId: string; image: string; originalName?: string; pageId?: string; userId: string }, - never - >; - HealthCheck: ApiRouteHandler< - Record, - ApiResponse<200, { status: string; timestamp: string; service: string }>, - never - >; - CleanupOrphanedImages: EventHandler<{ jobId: string; cleanupType: string }, never>; - CleanupMarkedImages: EventHandler< - { jobId: string; batchSize: number; cleanupType: string }, - never - >; - AsyncPageSave: ApiRouteHandler< - { pageId: string; newPageData: string; userId: string }, - | ApiResponse<202, { message: string; jobId: string; pageId: string }> - | ApiResponse<400, { error: string }>, - { - topic: 'process-page-save'; - data: { jobId: string; pageId: string; newPageData: string; userId: string }; - } - >; - AsyncImageUpload: ApiRouteHandler< - { image: string; originalName?: string; pageId?: string; userId: string }, - ApiResponse<202, { message: string; jobId: string }> | ApiResponse<400, { error: string }>, - { - topic: 'process-image-upload'; - data: { - jobId: string; - image: string; - originalName?: string; - pageId?: string; - userId: string; - }; - } - >; - } -} diff --git a/package.json b/package.json index 91e031c..a7e1e44 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,11 @@ "description": "", "main": "index.js", "scripts": { - "install:all": "pnpm install && cd backend && pnpm install && cd ../frontend && pnpm install && cd ../motia && pnpm install && cd ../", + "install:all": "pnpm install && cd backend && pnpm install && cd ../frontend && pnpm install && cd ../", "start:backend": "cd backend && pnpm dev", "start:frontend": "cd frontend && pnpm dev", - "start:motia": "cd motia && pnpm dev", - "start": "concurrently -n \"🔵 Backend,🟡 Frontend,🟠 Motia\" -c \"blue,yellow,red\" \"pnpm start:backend\" \"pnpm start:frontend\" \"pnpm start:motia\"", - "dev": "concurrently -n \"🔵 Backend,🟡 Frontend,🟠 Motia\" -c \"blue,yellow,red\" \"pnpm start:backend\" \"pnpm start:frontend\" \"pnpm start:motia\"", + "start": "concurrently -n \"🔵 Backend,🟡 Frontend\" -c \"blue,yellow\" \"pnpm start:backend\" \"pnpm start:frontend\"", + "dev": "concurrently -n \"🔵 Backend,🟡 Frontend\" -c \"blue,yellow\" \"pnpm start:backend\" \"pnpm start:frontend\"", "docker:build": "docker compose build", "docker:up": "docker compose up -d", "docker:down": "docker compose down", From 54e1dbaab0043e813689673a6dc6c9b8924d24ef Mon Sep 17 00:00:00 2001 From: MannuVilasara Date: Sat, 1 Nov 2025 10:31:36 +0530 Subject: [PATCH 2/3] update docker compose --- docker-compose.yml | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index cdcd34d..54b462f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,8 +5,8 @@ services: image: ghcr.io/braydenidzenga/zettanote-nginx:latest container_name: zettanote-nginx ports: - - "80:80" - - "443:443" + - '80:80' + - '443:443' volumes: - nginx_certbot:/etc/letsencrypt - nginx_certbot:/var/www/certbot @@ -21,7 +21,7 @@ services: image: ghcr.io/braydenidzenga/zettanote-backend:latest container_name: zettanote-backend expose: - - "4000" + - '4000' environment: - NODE_ENV=production - PORT=4000 @@ -48,14 +48,7 @@ services: restart: unless-stopped healthcheck: test: - [ - "CMD", - "wget", - "--no-verbose", - "--tries=1", - "--spider", - "http://localhost:4000/api/health", - ] + ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:4000/api/health'] interval: 30s timeout: 10s retries: 3 @@ -67,7 +60,7 @@ services: image: ghcr.io/braydenidzenga/zettanote-frontend:latest container_name: zettanote-frontend expose: - - "3000" + - '3000' environment: - NODE_ENV=production - PORT=3000 @@ -76,15 +69,7 @@ services: - backend restart: unless-stopped healthcheck: - test: - [ - "CMD", - "wget", - "--no-verbose", - "--tries=1", - "--spider", - "http://localhost:3000/", - ] + test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:3000/'] interval: 30s timeout: 10s retries: 3 @@ -95,10 +80,10 @@ services: image: redis:7.0-alpine container_name: zettanote-redis ports: - - "6379:6379" + - '6379:6379' restart: unless-stopped healthcheck: - test: ["CMD", "redis-cli", "ping"] + test: ['CMD', 'redis-cli', 'ping'] interval: 30s timeout: 10s retries: 3 @@ -115,10 +100,10 @@ services: volumes: - mongodb_data:/data/db expose: - - "27017" + - '27017' restart: unless-stopped healthcheck: - test: ["CMD", "mongosh", "--eval", 'db.adminCommand("ping")'] + test: ['CMD', 'mongosh', '--eval', 'db.adminCommand("ping")'] interval: 30s timeout: 10s retries: 3 From 1c595146669888c31418bd89e4ac74e2cd1aea3d Mon Sep 17 00:00:00 2001 From: MannuVilasara Date: Sat, 1 Nov 2025 10:46:14 +0530 Subject: [PATCH 3/3] no more action for it --- .github/workflows/docker-build.yml | 47 ------------------------------ 1 file changed, 47 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 6299d25..b2eb009 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -18,7 +18,6 @@ jobs: backend: ${{ steps.filter.outputs.backend }} frontend: ${{ steps.filter.outputs.frontend }} nginx: ${{ steps.filter.outputs.nginx }} - motia: ${{ steps.filter.outputs.motia }} # admin-portal: ${{ steps.filter.outputs.admin-portal }} steps: - name: Checkout code @@ -35,8 +34,6 @@ jobs: - 'frontend/**' nginx: - 'nginx/**' - motia: - - 'motia/**' build-and-push-backend: runs-on: ubuntu-latest @@ -169,49 +166,6 @@ jobs: tags: ${{ steps.meta-nginx.outputs.tags }} labels: ${{ steps.meta-nginx.outputs.labels }} - build-and-push-motia: - runs-on: ubuntu-latest - # needs: detect-changes - if: github.ref == 'refs/heads/main' && github.repository == 'braydenidzenga/ZettaNote' - permissions: - contents: read - packages: write - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set lowercase repository owner - id: repo-owner - run: echo "owner_lc=${OWNER,,}" >> $GITHUB_OUTPUT - env: - OWNER: ${{ github.repository_owner }} - - - name: Log in to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata for motia - id: meta-motia - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ steps.repo-owner.outputs.owner_lc }}/zettanote-motia - tags: | - type=ref,event=branch - type=sha,prefix={{branch}}- - type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/v2-CI' }} - - - name: Build and push motia image - uses: docker/build-push-action@v5 - with: - context: ./motia - file: ./motia/Dockerfile - push: true - tags: ${{ steps.meta-motia.outputs.tags }} - labels: ${{ steps.meta-motia.outputs.labels }} - # build-and-push-admin: # runs-on: ubuntu-latest # needs: detect-changes @@ -282,7 +236,6 @@ jobs: - build-and-push-backend - build-and-push-frontend - build-and-push-nginx - - build-and-push-motia steps: - name: Deploy to server via SSH uses: appleboy/ssh-action@v1.0.3