From 3e964d1176454ffd1648bb6f4e82e9e51337b9c0 Mon Sep 17 00:00:00 2001 From: jayjennings Date: Tue, 6 Oct 2026 11:38:40 -0700 Subject: [PATCH] feat(i18n): add internationalization support with English and Spanish translations feat(kiosk): implement kiosk report submission functionality with offline support test(outbox): add tests for outbox functionality including report submission and error handling feat(outbox): create outbox management for queued reports with IndexedDB persistence feat(uuid): add UUID generation utility for client IDs feat(qr): implement QR code generation for reporting links by site and area feat(kiosk): create Kiosk page for reporting incidents without an account --- .oxlintrc.json | 3 +- CONTRIBUTING.md | 1 + README.md | 9 +- docs/API.md | 21 +- docs/ROADMAP.md | 14 +- docs/TODO.md | 8 + e2e/global-setup.ts | 7 +- e2e/shop-floor.spec.ts | 92 + index.html | 2 + package-lock.json | 5486 ++++++++++++++++- package.json | 7 +- public/icons/apple-touch-icon.png | Bin 0 -> 3403 bytes public/icons/icon-192.png | Bin 0 -> 5982 bytes public/icons/icon-512.png | Bin 0 -> 17162 bytes public/icons/maskable-512.png | Bin 0 -> 9742 bytes scripts/generate-icons.mjs | 28 + server/app.ts | 3 + .../db/migrations/0002_kiosks_and_offline.sql | 24 + server/db/migrations/meta/0002_snapshot.json | 2131 +++++++ server/db/migrations/meta/_journal.json | 7 + server/db/schema.ts | 31 + server/lib/attachments.ts | 39 + server/lib/incidents.ts | 10 +- server/lib/reporting.ts | 115 + server/routes/incidents.ts | 91 +- server/routes/kiosks.test.ts | 124 + server/routes/kiosks.ts | 177 + shared/api-types.ts | 22 + shared/schemas.ts | 12 +- src/App.tsx | 4 + src/components/AppLayout.tsx | 7 + src/components/AuthLayout.tsx | 4 + src/components/Badges.tsx | 2 +- src/components/FormSection.tsx | 12 +- src/components/Header.tsx | 10 +- src/components/IncidentTable.tsx | 2 +- src/components/LanguageToggle.tsx | 12 + src/components/OutboxBanner.tsx | 45 + src/components/QrCode.tsx | 19 + src/components/Sidebar.tsx | 31 +- src/components/incident/ActionsSection.tsx | 9 +- src/i18n/en.ts | 170 + src/i18n/es.ts | 167 + src/i18n/i18n.test.ts | 31 + src/i18n/index.ts | 20 + src/i18n/provider.tsx | 41 + src/lib/kiosk.ts | 20 + src/lib/navigation.ts | 15 +- src/lib/outbox.test.ts | 79 + src/lib/outbox.ts | 213 + src/lib/queries.ts | 27 +- src/lib/use-outbox.ts | 45 + src/lib/uuid.test.ts | 15 + src/lib/uuid.ts | 12 + src/main.tsx | 9 +- src/pages/Actions.tsx | 31 +- src/pages/Auth.tsx | 42 +- src/pages/IncidentDetail.tsx | 3 +- src/pages/Kiosk.tsx | 253 + src/pages/Locations.tsx | 20 +- src/pages/QrSheet.tsx | 101 + src/pages/ReportIncident.tsx | 214 +- src/pages/Settings.tsx | 134 +- vite.config.ts | 40 +- 64 files changed, 10056 insertions(+), 267 deletions(-) create mode 100644 e2e/shop-floor.spec.ts create mode 100644 public/icons/apple-touch-icon.png create mode 100644 public/icons/icon-192.png create mode 100644 public/icons/icon-512.png create mode 100644 public/icons/maskable-512.png create mode 100644 scripts/generate-icons.mjs create mode 100644 server/db/migrations/0002_kiosks_and_offline.sql create mode 100644 server/db/migrations/meta/0002_snapshot.json create mode 100644 server/lib/attachments.ts create mode 100644 server/lib/reporting.ts create mode 100644 server/routes/kiosks.test.ts create mode 100644 server/routes/kiosks.ts create mode 100644 src/components/LanguageToggle.tsx create mode 100644 src/components/OutboxBanner.tsx create mode 100644 src/components/QrCode.tsx create mode 100644 src/i18n/en.ts create mode 100644 src/i18n/es.ts create mode 100644 src/i18n/i18n.test.ts create mode 100644 src/i18n/index.ts create mode 100644 src/i18n/provider.tsx create mode 100644 src/lib/kiosk.ts create mode 100644 src/lib/outbox.test.ts create mode 100644 src/lib/outbox.ts create mode 100644 src/lib/use-outbox.ts create mode 100644 src/lib/uuid.test.ts create mode 100644 src/lib/uuid.ts create mode 100644 src/pages/Kiosk.tsx create mode 100644 src/pages/QrSheet.tsx diff --git a/.oxlintrc.json b/.oxlintrc.json index b707251..3cc9692 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -5,7 +5,8 @@ "react/rules-of-hooks": "error", "react/only-export-components": ["warn", { "allowConstantExport": true }], "jsx-a11y/control-has-associated-label": "off", - "jsx-a11y/prefer-tag-over-role": "off" + "jsx-a11y/prefer-tag-over-role": "off", + "jsx-a11y/label-has-associated-control": ["error", { "depth": 4 }] }, "ignorePatterns": ["dist", "playwright-report", "test-results"] } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1c8acf8..ee1ff53 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,6 +39,7 @@ CI runs the same checks on every pull request. - **Permissions:** every API route must check the signed-in user's role and organization. Add a test showing a lower role is refused. - **Styling:** Tailwind CSS. Use the theme tokens in `src/index.css` (`text-ink`, `bg-coral`, `border-line`, …) rather than new hex values; add a token if a color is reused. - **Tests:** put domain logic in `src/lib/` with a unit test next to it (`*.test.ts`). Cover user-facing flows with a component test or a Playwright test in `e2e/`. +- **Translations:** user-facing text on worker screens lives in `src/i18n/en.ts` with the Spanish in `src/i18n/es.ts`. TypeScript and a test fail if a Spanish entry is missing, so add both together. If you can't translate, open the pull request anyway and ask for help. - **Accessibility:** every form control needs a label, and every icon-only button needs an `aria-label`. Shop-floor users may be on gloves-on touchscreens, so keep touch targets generous. - **Safety data:** incident and injury records can contain medical and personal information. Never log them, and never add third-party scripts, fonts or analytics that would send data off the server. diff --git a/README.md b/README.md index 2d463e3..c446179 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Free, open-source accident and safety tracking for manufacturing: incident and near-miss reporting, investigations, corrective actions and (planned) OSHA record keeping. -> **Status: early development (Phases 0–2 done).** Reporting, investigation, corrective actions, email notifications, dashboards and CSV export work end to end. OSHA record keeping and offline shop-floor reporting are next. See [docs/ROADMAP.md](docs/ROADMAP.md) for the plan and [docs/TODO.md](docs/TODO.md) for open items. +> **Status: early development (Phases 0–3 done).** Reporting (including offline, kiosk tablets, QR codes and Spanish), investigation, corrective actions, email notifications, dashboards and CSV export work end to end. OSHA record keeping is next. See [docs/ROADMAP.md](docs/ROADMAP.md) for the plan and [docs/TODO.md](docs/TODO.md) for open items. ## Getting started @@ -33,6 +33,13 @@ This runs the app and PostgreSQL. The app applies database migrations on startup - Set `SMTP_URL` and `MAIL_FROM` so sign-in links, invitations and notifications are delivered. - Set `TZ` to the plant's time zone (e.g. `America/Chicago`) so due dates and daily reminders follow local days. - Back up both volumes: `db-data` (PostgreSQL) and `app-data` (uploads). +- Installing the app on phones and opening it offline needs HTTPS (browsers require it for service workers). Over plain HTTP everything else works, and reports made while offline are still queued once the page is open. + +## Shop-floor reporting + +- **Kiosk tablets and QR codes:** in **Settings → Reporting links**, create a link. Open it on a shared tablet for a kiosk, or print QR codes for it from **Locations → QR codes**. Anyone can then report without an account; the link can't read anything and can be revoked at any time. +- **Offline:** reports made without a connection are kept on the device and sent automatically when it returns. +- **Spanish:** use the language button (sidebar, sign-in page or kiosk header). The choice is remembered on that device. For a very small single-machine install, the app image also runs on its own with embedded PostgreSQL: `docker run -p 3000:3000 -v safetylog-data:/app/data `. diff --git a/docs/API.md b/docs/API.md index 38c7cee..110957f 100644 --- a/docs/API.md +++ b/docs/API.md @@ -68,6 +68,8 @@ Addressed by number (`/api/incidents/42` is `INC-0042`). Numbers are sequential **List and export filters:** `page`, `pageSize` (1–100, default 25), `q` (title, description, location; `INC-0042` or `42` matches the number), `type`, `severity`, `status`, `siteId`. +Send a random `clientId` (UUID) with each report. Resubmitting the same `clientId` returns the original report (200 instead of 201) instead of creating a duplicate, so devices can safely retry after a dropped connection. + **Create body:** ```json @@ -81,7 +83,8 @@ Addressed by number (`/api/incidents/42` is `INC-0042`). Numbers are sequential "locationDetail": "Loading bay C", "description": "…", "immediateAction": "Area cordoned off", - "anonymous": false + "anonymous": false, + "clientId": "6f1c…" } ``` @@ -119,6 +122,22 @@ Addressed by number (`/api/incidents/42` is `INC-0042`). Numbers are sequential Each action has `overdue: true` when it's open or in progress and its due date has passed (server time zone, `TZ`). Assignees get one email digest per day listing their actions due tomorrow or overdue. +## Reporting links (kiosks and QR codes) + +Reporting links let people file reports without an account. Each has a token that can **only** create reports. + +| Method | Path | Who | Notes | +| --- | --- | --- | --- | +| GET | `/api/kiosks` | safety_manager | All links, including their tokens (to reprint QR codes) | +| POST | `/api/kiosks` | safety_manager | `{ name, siteId? }`. `siteId` restricts the link to one site | +| PATCH | `/api/kiosks/:id` | safety_manager | `{ name?, siteId?, revoked? }` | +| GET | `/api/kiosk/config` | link token | Organization name, link name, and the sites/areas it may report on | +| POST | `/api/kiosk/reports` | link token | Multipart: `report` (JSON: the create body minus `anonymous`, plus optional `reporterName`) and up to 5 `files`. Returns `{ reference, failedFiles }`. 30 reports per link per 10 minutes | + +The token goes in the `X-Kiosk-Token` header. Browsers can't send custom headers cross-site without a CORS preflight, which the API doesn't allow, so other websites can't submit through a link. Reports without `reporterName` are anonymous. Incidents filed this way have `channel: "kiosk"` and `kiosk: { id, name }`. + +The web app opens links at `/k/`, optionally with `?site=&area=` to pre-fill the location (as QR codes do). + ## Stats | Method | Path | Who | Notes | diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 72052dd..9b90fab 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -17,6 +17,9 @@ This is a living document. Update it as decisions are made or scope changes. | Compliance scope | US OSHA first; data model kept extensible for other regions (e.g. RIDDOR) | Proposed | | Incident PDFs | Browser print-to-PDF from a print stylesheet; server-side PDF deferred (see TODO) | Decided | | Email | SMTP via `SMTP_URL`; without it, logged in development and dropped in production. Delivery setup deferred (see TODO) | Decided | +| Reporting without accounts | "Reporting links": revocable, rate-limited tokens that can only file reports; used for kiosk tablets and QR codes | Decided | +| Languages | English + Spanish with typed message files; worker-facing screens first, manager screens later (see TODO) | Decided | +| Offline | Installable PWA; reports queued in IndexedDB and retried with a client-generated id so retries never duplicate | Decided | | CI | Gitea Actions (`.gitea/workflows`): lint, typecheck, unit tests, build, e2e | Decided | | Product name | Open SafetyLog EHS (replaced placeholder "IA Tracker" and the prototype's "Safesite" branding) | Decided | @@ -61,10 +64,13 @@ This is a living document. Update it as decisions are made or scope changes. ## Phase 3: Shop-floor reporting -- Installable PWA with offline queue (sync when connection returns) -- Printable QR codes per area that pre-fill the location -- Kiosk mode and anonymous reporting -- Multi-language support, Spanish first +- [x] Installable app (web manifest, icons, service worker caching the app shell plus who-am-I and site lists) +- [x] Offline outbox: reports and photos saved on the device, sent automatically on reconnect; duplicate-proof retries via a client-generated id; reports only sent for the user who made them; warning on sign-out with unsent reports +- [x] Reporting links (managed in Settings): revocable tokens, optionally limited to one site, 30 reports per 10 minutes, photos included; kiosk page for shared tablets with large touch targets and auto-reset +- [x] Printable QR code sheets per site/area, for signed-in users or through a reporting link, with bilingual captions; scanning pre-fills the location +- [x] Anonymous reporting from the app, the kiosk and QR codes +- [x] English/Spanish: sign-in pages, navigation, report form, kiosk, My actions, offline messages; language toggle remembered per device; follows the browser language by default +- [x] Tests: outbox (IndexedDB), translations complete, reporting links and duplicate-proof retries on the server, browser tests for offline sync, Spanish kiosk via QR, QR pre-fill and installability ## Phase 4: Compliance (US OSHA) diff --git a/docs/TODO.md b/docs/TODO.md index 90f190b..6f553b9 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -23,6 +23,14 @@ Open items that aren't tied to a single roadmap phase. Tick them off (or delete - [ ] **HEIC thumbnails.** iPhone HEIC photos are stored and downloadable but browsers can't show them inline; convert to JPEG on upload. - [ ] **Session check console noise.** Signed-out visitors see one 401 in the browser console from the session check; harmless, but a `200 { user: null }` endpoint would be quieter. +## Phase 3 follow-ups + +- [ ] **Translate manager screens.** Spanish currently covers what shop-floor workers use (sign-in, report form, kiosk, My actions, navigation). The incident page, investigation, dashboards, analytics, locations and settings are still English. Add their strings to `src/i18n/en.ts` and `es.ts`. +- [ ] **Spanish emails.** Notification and sign-in emails are English only. Store a language preference per user and use it for emails. +- [ ] **HTTPS for offline use.** Browsers only allow installing the app and the offline app shell over HTTPS (or localhost). Reports still queue offline over plain HTTP once the page is open, but the page itself can't load offline. Document a simple HTTPS setup (e.g. Caddy in front of the app) in the install guide. +- [ ] **Have Spanish reviewed by a native speaker** familiar with plant safety terms (e.g. "casi accidente" for near miss, "planta" for site). +- [ ] **Offline incident list.** Only reporting works offline; viewing incidents and actions needs a connection. + ## Done - [x] Docker verified 2026-10-06 (Docker 29.8, Compose v5.5): image builds (~315 MB), `docker compose up` with PostgreSQL 18 passes setup → sign-in → report smoke test; data and sessions survive `down`/`up`; clean shutdown; healthcheck healthy; runs as non-root; standalone PGlite container works; `Secure` cookie with an `https://` PUBLIC_URL; web app loads with no errors. diff --git a/e2e/global-setup.ts b/e2e/global-setup.ts index 1c593d5..1c8b623 100644 --- a/e2e/global-setup.ts +++ b/e2e/global-setup.ts @@ -12,7 +12,12 @@ export default async function globalSetup() { } await ok(await api.post('/api/setup', { data: { organizationName: 'E2E Plant', ...users.admin, password: PASSWORD } })) const { site } = await ok(await api.post('/api/sites', { data: { name: 'Main Plant' } })) - await ok(await api.post(`/api/sites/${site.id}/areas`, { data: { name: 'Press Shop', kind: 'building' } })) + const { area } = await ok(await api.post(`/api/sites/${site.id}/areas`, { data: { name: 'Press Shop', kind: 'building' } })) + const { kiosk } = await ok(await api.post('/api/kiosks', { data: { name: 'Canteen tablet' }, headers: { origin: baseURL } })) + // Shared with the test workers + process.env.E2E_KIOSK_TOKEN = kiosk.token + process.env.E2E_SITE_ID = site.id + process.env.E2E_AREA_ID = area.id for (const role of ['supervisor', 'reporter'] as const) { await ok(await api.post('/api/users', { data: { ...users[role], role, password: PASSWORD } })) } diff --git a/e2e/shop-floor.spec.ts b/e2e/shop-floor.spec.ts new file mode 100644 index 0000000..5e80141 --- /dev/null +++ b/e2e/shop-floor.spec.ts @@ -0,0 +1,92 @@ +import { expect, test } from '@playwright/test' +import { signIn, unique, users } from './fixtures' + +const token = () => process.env.E2E_KIOSK_TOKEN! +const site = () => process.env.E2E_SITE_ID! +const area = () => process.env.E2E_AREA_ID! + +test('saves a report offline and sends it when the connection returns', async ({ page, context }) => { + const title = unique('Offline report: frayed sling') + await signIn(page, 'reporter') + await page.goto('/report') + await expect(page.getByLabel('Incident title')).toBeVisible() + + await context.setOffline(true) + await page.getByLabel('Incident title').fill(title) + await page.getByRole('button', { name: 'Submit report' }).click() + await expect(page.getByRole('heading', { name: 'Saved on this device' })).toBeVisible() + await expect(page.getByText('1 report waiting to send')).toBeVisible() + + await context.setOffline(false) + await expect(page.getByText('1 report waiting to send')).toBeHidden({ timeout: 15_000 }) + await page.goto('/incidents') + await expect(page.getByRole('link', { name: title })).toBeVisible() +}) + +test('kiosk: reports without an account, in Spanish, from a QR code', async ({ browser, page }) => { + const title = unique('Cable suelto en el pasillo') + const kiosk = await (await browser.newContext({ locale: 'es-MX' })).newPage() + await kiosk.goto(`/k/${token()}?site=${site()}&area=${area()}`) + await expect(kiosk.getByRole('heading', { name: 'Reporte un problema de seguridad' })).toBeVisible() + await expect(kiosk.getByLabel('Edificio o área')).toHaveValue(area()) + + await kiosk.getByText('Peligro', { exact: true }).click() + await kiosk.getByText('Alta', { exact: true }).click() + await kiosk.getByLabel('En pocas palabras, ¿qué vio?').fill(title) + await kiosk.getByLabel('Su nombre').fill('Luis') + await kiosk.getByRole('button', { name: 'Enviar reporte' }).click() + await expect(kiosk.getByRole('heading', { name: 'Gracias' })).toBeVisible() + const reference = (await kiosk.getByText(/Su reporte INC-\d{4}/).textContent())!.match(/INC-\d{4}/)![0] + + // Switching language works on the kiosk too + await kiosk.getByRole('button', { name: 'Reportar otra cosa' }).click() + await kiosk.getByRole('button', { name: 'English' }).click() + await expect(kiosk.getByRole('heading', { name: 'Report a safety concern' })).toBeVisible() + + // The safety team sees who reported it and through which link + await signIn(page, 'admin') + await page.goto(`/incidents/${Number(reference.slice(4))}`) + await expect(page.getByRole('heading', { level: 1 })).toHaveText(title) + await expect(page.getByText('Reported by Luis via Canteen tablet')).toBeVisible() + await expect(page.getByText('Press Shop').first()).toBeVisible() +}) + +test('kiosk: a made-up or revoked link explains itself', async ({ page }) => { + await page.goto('/k/not-a-real-token') + await expect(page.getByText('This reporting link isn’t working')).toBeVisible() +}) + +test('QR codes open the report form with the location filled in', async ({ page, isMobile }) => { + test.skip(isMobile, 'Printing QR sheets is a desktop task') + await signIn(page, 'admin') + await page.goto(`/locations/qr?site=${site()}`) + await expect(page.getByRole('img', { name: /QR code for/ })).toHaveCount(2) // whole site + Press Shop + const url = await page.locator('main').getByText(/\/report\?site=/).nth(1).textContent() + expect(url).toContain(`area=${area()}`) + + await page.goto(url!.trim()) + await expect(page.getByText('Location filled in from the QR code.')).toBeVisible() + await expect(page.getByLabel('Building or area')).toHaveValue(area()) +}) + +test('the signed-in app speaks Spanish too', async ({ page, isMobile }) => { + await signIn(page, 'reporter') + if (isMobile) await page.getByRole('button', { name: 'Open menu' }).click() + await page.getByRole('button', { name: 'Español' }).click() + if (isMobile) await page.getByRole('button', { name: 'Cerrar menú' }).click() + await page.goto('/report') + await expect(page.getByRole('heading', { name: 'Reportar un incidente' })).toBeVisible() + await expect(page.locator('html')).toHaveAttribute('lang', 'es') + await page.goto('/actions') + await expect(page.getByRole('heading', { name: 'Mis acciones' })).toBeVisible() + expect(users.reporter.email).toBeTruthy() +}) + +test('is installable: manifest and service worker', async ({ page }) => { + await page.goto('/login') + const manifest = await (await page.request.get('/manifest.webmanifest')).json() + expect(manifest).toMatchObject({ name: 'Open SafetyLog EHS', display: 'standalone' }) + expect(manifest.icons.map((icon: { sizes: string }) => icon.sizes)).toEqual(expect.arrayContaining(['192x192', '512x512'])) + const scope = await page.evaluate(async () => (await navigator.serviceWorker.ready).scope) + expect(scope).toMatch(/\/$/) +}) diff --git a/index.html b/index.html index 624e8d3..51288d0 100644 --- a/index.html +++ b/index.html @@ -3,6 +3,8 @@ + + Open SafetyLog EHS diff --git a/package-lock.json b/package-lock.json index eb4ded9..82e1104 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,21 +31,26 @@ "@types/node": "^26.6.4", "@types/nodemailer": "^8.0.2", "@types/pg": "^8.23.1", + "@types/qrcode": "^1.5.6", "@types/react": "^19.2.18", "@types/react-dom": "^19.2.4", "@vitejs/plugin-react": "^6.1.0", "concurrently": "^10.0.5", "drizzle-kit": "^0.31.11", + "fake-indexeddb": "^6.2.5", "jsdom": "^30.1.2", "lucide-react": "^1.39.0", "oxlint": "^1.79.0", + "qrcode": "^1.5.4", "react": "^19.2.8", "react-dom": "^19.2.8", "react-router-dom": "^7.18.3", "tailwindcss": "^4.3.3", "typescript": "^7.0.2", "vite": "^8.2.2", - "vitest": "^5.0.3" + "vite-plugin-pwa": "^2.0.0", + "vitest": "^5.0.3", + "workbox-window": "^7.4.1" }, "engines": { "node": ">=22.18" @@ -58,6 +63,23 @@ "dev": true, "license": "MIT" }, + "node_modules/@apideck/better-ajv-errors": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.7.tgz", + "integrity": "sha512-TajUJwGWbDwkCx/CZi7tRE8PVB7simCvKJfHUsSdvps+aTM/PDPP4gkLmKnc+x3CE//y9i/nj74GqdL/hwk7Iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsonpointer": "^5.0.1", + "leven": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "ajv": ">=8" + } + }, "node_modules/@asamuzakjp/css-color": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-7.1.3.tgz", @@ -97,7 +119,6 @@ "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", @@ -107,17 +128,1485 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz", + "integrity": "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", + "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.11" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz", + "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-wrap-function": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz", + "integrity": "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", + "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.29.7.tgz", + "integrity": "sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.29.7.tgz", + "integrity": "sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.29.7.tgz", + "integrity": "sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.7.tgz", + "integrity": "sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.29.7.tgz", + "integrity": "sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.29.7.tgz", + "integrity": "sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.29.7.tgz", + "integrity": "sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.29.7.tgz", + "integrity": "sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.7.tgz", + "integrity": "sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.29.7.tgz", + "integrity": "sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.29.7.tgz", + "integrity": "sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz", + "integrity": "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", + "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.29.7.tgz", + "integrity": "sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz", + "integrity": "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.29.7.tgz", + "integrity": "sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/template": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz", + "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.29.7.tgz", + "integrity": "sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.29.7.tgz", + "integrity": "sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.29.7.tgz", + "integrity": "sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.29.7.tgz", + "integrity": "sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.29.7.tgz", + "integrity": "sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz", + "integrity": "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz", + "integrity": "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.29.7.tgz", + "integrity": "sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.29.7.tgz", + "integrity": "sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.29.7.tgz", + "integrity": "sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz", + "integrity": "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.29.7.tgz", + "integrity": "sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.29.7.tgz", + "integrity": "sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.8.tgz", + "integrity": "sha512-6iSnEK0zlkLKU4heofK/AdmRD4e2SHVpJMtrwnTCzhnaM98ria4rTrOXBBi45BTTYnJtO8txnPsX4fChYXkmeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.29.7.tgz", + "integrity": "sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.29.7.tgz", + "integrity": "sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz", + "integrity": "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.29.7.tgz", + "integrity": "sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz", + "integrity": "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.29.7.tgz", + "integrity": "sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz", + "integrity": "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz", + "integrity": "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz", + "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz", + "integrity": "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz", + "integrity": "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.29.7.tgz", + "integrity": "sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.8.tgz", + "integrity": "sha512-0UpIXPtdDtMXfnV2OJAVMLpj3H/92vmkA6lpSRakmycJvj3VUy6Xs1dM8tXRugupykr5WB+LpiVl0J8LMVg2mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.29.7.tgz", + "integrity": "sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.29.7.tgz", + "integrity": "sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.29.7.tgz", + "integrity": "sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.8.tgz", + "integrity": "sha512-4S9ksMGVWUshvgK0mKfvZky7leuG5/uoFVwMpAomJ8bMoDJiNHRVmc1EglwW/CmGVSqqWpEbXm9FmbRit22qoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.29.7.tgz", + "integrity": "sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.29.7.tgz", + "integrity": "sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.29.7.tgz", + "integrity": "sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.29.7.tgz", + "integrity": "sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.29.7.tgz", + "integrity": "sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz", + "integrity": "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.29.7.tgz", + "integrity": "sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.7.tgz", + "integrity": "sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.29.7", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.29.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.29.7", + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.29.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.29.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.29.7", + "@babel/plugin-syntax-import-attributes": "^7.29.7", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.29.7", + "@babel/plugin-transform-async-generator-functions": "^7.29.7", + "@babel/plugin-transform-async-to-generator": "^7.29.7", + "@babel/plugin-transform-block-scoped-functions": "^7.29.7", + "@babel/plugin-transform-block-scoping": "^7.29.7", + "@babel/plugin-transform-class-properties": "^7.29.7", + "@babel/plugin-transform-class-static-block": "^7.29.7", + "@babel/plugin-transform-classes": "^7.29.7", + "@babel/plugin-transform-computed-properties": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-dotall-regex": "^7.29.7", + "@babel/plugin-transform-duplicate-keys": "^7.29.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-dynamic-import": "^7.29.7", + "@babel/plugin-transform-explicit-resource-management": "^7.29.7", + "@babel/plugin-transform-exponentiation-operator": "^7.29.7", + "@babel/plugin-transform-export-namespace-from": "^7.29.7", + "@babel/plugin-transform-for-of": "^7.29.7", + "@babel/plugin-transform-function-name": "^7.29.7", + "@babel/plugin-transform-json-strings": "^7.29.7", + "@babel/plugin-transform-literals": "^7.29.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.29.7", + "@babel/plugin-transform-member-expression-literals": "^7.29.7", + "@babel/plugin-transform-modules-amd": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-modules-systemjs": "^7.29.7", + "@babel/plugin-transform-modules-umd": "^7.29.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-new-target": "^7.29.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.29.7", + "@babel/plugin-transform-numeric-separator": "^7.29.7", + "@babel/plugin-transform-object-rest-spread": "^7.29.7", + "@babel/plugin-transform-object-super": "^7.29.7", + "@babel/plugin-transform-optional-catch-binding": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/plugin-transform-private-methods": "^7.29.7", + "@babel/plugin-transform-private-property-in-object": "^7.29.7", + "@babel/plugin-transform-property-literals": "^7.29.7", + "@babel/plugin-transform-regenerator": "^7.29.7", + "@babel/plugin-transform-regexp-modifiers": "^7.29.7", + "@babel/plugin-transform-reserved-words": "^7.29.7", + "@babel/plugin-transform-shorthand-properties": "^7.29.7", + "@babel/plugin-transform-spread": "^7.29.7", + "@babel/plugin-transform-sticky-regex": "^7.29.7", + "@babel/plugin-transform-template-literals": "^7.29.7", + "@babel/plugin-transform-typeof-symbol": "^7.29.7", + "@babel/plugin-transform-unicode-escapes": "^7.29.7", + "@babel/plugin-transform-unicode-property-regex": "^7.29.7", + "@babel/plugin-transform-unicode-regex": "^7.29.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.29.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.15", + "babel-plugin-polyfill-corejs3": "^0.14.0", + "babel-plugin-polyfill-regenerator": "^0.6.6", + "core-js-compat": "^3.48.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, "node_modules/@babel/runtime": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", @@ -128,6 +1617,54 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@bramus/specificity": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.3.tgz", @@ -1242,6 +2779,16 @@ "zod": "^3.25.0 || ^4.0.0" } }, + "node_modules/@isaacs/cliui": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz", + "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -1274,6 +2821,17 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", @@ -1292,6 +2850,26 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, "node_modules/@oxc-project/types": { "version": "0.148.0", "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.148.0.tgz", @@ -1945,6 +3523,522 @@ "dev": true, "license": "MIT" }, + "node_modules/@rollup/plugin-babel": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-6.1.0.tgz", + "integrity": "sha512-dFZNuFD2YRcoomP4oYf+DvQNSUA9ih+A3vUqopQx5EdtPGo3WBnQcI/S8pwpz91UsGfL0HsMSOlaMld8HrbubA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@rollup/pluginutils": "^5.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + }, + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", + "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.3.tgz", + "integrity": "sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-terser": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-1.0.0.tgz", + "integrity": "sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "serialize-javascript": "^7.0.3", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.64.0.tgz", + "integrity": "sha512-FLLpX941CD/7aBvX3GqLGBM9OvY5PGXTryPJkG5r5/OuBpZpV5k45Uo3RxAvqd35tsyc3hH1bhtz921IKzoIzg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.64.0.tgz", + "integrity": "sha512-iI32XM/jnDYJsvx5ai/za/7gWO9XoSeFFtU06/ZCaRgyilfJOjaopD3nOpk2WrTCGOyeDt4hleUiGOAnd5tHNg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.64.0.tgz", + "integrity": "sha512-dRBZlbt2sEtF8Mn4MODThze9fIPdDoOhVSlXMAKy5dQbOYK9pOOoPY4Fat3OTtr0+8zbJo5TTZwlsfxY/kDNJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.64.0.tgz", + "integrity": "sha512-Y3whrJOMucfkhgNkvcM93M6j8C53iEAMmPMYD99C6G1kUy4ELigLWk9ar2/4aCBSRgsql0zdlOemLgW2m5GZgQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.64.0.tgz", + "integrity": "sha512-S6S1GEzPjFF6IONYJX3AKt/799+8RgBgCcwRnUo+Ep1IvBxUbw5M51iU0TDdK2NWWVnSvCQ8yi6Em0fGASMOng==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.64.0.tgz", + "integrity": "sha512-Ed1DPoFENkXj4IGzSB12SesV40iP6LxCCrbTIkSGIQBpOOxpBM+0kj62lmaeIHfMWTDoddqTOtqc7s8LYfn+Pw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.64.0.tgz", + "integrity": "sha512-J/6xhutJPtFyIkmHdf4olOdHHKH5kOJNumojdWn+Elv5ICEYTVOa362Vw27TxsK0BLzb1le3EDlO3UbvFK1lnQ==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.64.0.tgz", + "integrity": "sha512-G4L/Nnx59d2LvDoV/P4S5lZ7oVLT6hodOHMacqjiq2LL2gts86KbkEBTYL53+fBt0odhf7XPIbIATGoYiJctxg==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.64.0.tgz", + "integrity": "sha512-zF16pvJDEUksGYRbfnXne7pdklAyj2XDmJeYKgP93oq0cUyX9Y8O7lUo1R+IY1GagP/YBvCEDCe7eEcAKpw//g==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.64.0.tgz", + "integrity": "sha512-nIggWn8n+w12+R5lsV+PYYoUY8vuObxPAQqJI7WES+9v0qspYuAHoZMfYM0yLxlipasT5BY9ht5W8t5c/rSCkg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.64.0.tgz", + "integrity": "sha512-WLOTiHPzszP0dxIMsHpFeDSOSB5I49Mj8K4+yKE3H1X/D0JRG5XZ5jrctJLMjnUc/LUzaKiwq6EHWNJ8pup8PA==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.64.0.tgz", + "integrity": "sha512-35RK9aRhh7g7Pmeu5gQ01aCvrhXzj9LoBE6xtUcEH1ns+nyTaSzxSpADmBQINu4QiTDGvmQYwo1j5hlg1rRXFw==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.64.0.tgz", + "integrity": "sha512-RqTfnpoTjuWfPAmqK5p2edt2AMCDJWm6oTn7sKfmyx+6tRga0ip05SJ977o6udTcIiDeF/CJMUfkaN4gtWt6Aw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.64.0.tgz", + "integrity": "sha512-RQjZPigjxFvFZDijG6rjlSXxhRaTf9zLYVpGK+lVcga64oMqP1GbgVqCb46eHTTceSIgp89Ja0y5aPe3GFBYHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.64.0.tgz", + "integrity": "sha512-tjL58mgQcTRnDRpeky+Sth1MKQeYi2Ct6r3Luq9E5aTSjnM/i/JbozqZkKqp9thM5+oDSZxo+05f9kdQedfTGA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.64.0.tgz", + "integrity": "sha512-ictoRyVaoZ8C67myHef+8hhCa6IplXJJ/xUCkVCxziV4zxMZh+jvhkhGsPBLqj1S72fnqD0QH5zL4lcaa4X7DQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.64.0.tgz", + "integrity": "sha512-8aVvZ2hfr9RLFzBQkQNmYeHLDja8fLeQAmLt757zdKN/B+8L809KlLJKctQjS22wZotptV8G6o7fVPuAs8S1tQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.64.0.tgz", + "integrity": "sha512-2dEF8GAcDKwshUfydD+GhosppNyBzhVUHkdFF3CXd3FpOkzj/RZzF5aoEtzklujklT5qFVRU2GK/cFeLaTNKVg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.64.0.tgz", + "integrity": "sha512-3XHTvoo2hKkh0MiOfS7SkhHjMaaWF7P4F3drocZZaho/Z8w7h/jpnuBHm91BOQLfvrKHs1yR+zir4E8RI3XzTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.64.0.tgz", + "integrity": "sha512-HKtkzodL4a3KFWDXDoO61cRynAWTR3LnAE0oGtfG9lcNFpNuVYUFOByxDgNqEvic9rvaQbAj+SFwTEWDptRaIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.64.0.tgz", + "integrity": "sha512-JBsxqiY16uyyCujtoC3s7zL+SrYyNElptD7K4V+KUoJ2V8/XG3hPWpheK+SuPwNh1cikJvIZmIdsrYXvD6PLJw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.64.0.tgz", + "integrity": "sha512-S5Qrijh37qhnUYQ0ay8WN3LuWeKjow7wTUyCOPMZtnXiBXYXdsZETI6ZLfYnQAKovltckPLBFdNeD61P2rJc7g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.64.0.tgz", + "integrity": "sha512-zbZ6iMmLFEsCtTdc2/y1F/cDFVNNCPF7Ae8PCT/wdPE//hGwYp6r+MyCLMFX+kOeIe09Pz6ASfnnfpSTN1FJQQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.64.0.tgz", + "integrity": "sha512-L6Hw69oNpuYaOr1zCG30v0/DqKYCSRwodPGwIcVZ/6f8SOzq9rxtL/xNVI5MO4wjli+Ko0ErK9uHJL3mNPt8wQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.64.0.tgz", + "integrity": "sha512-nl+CTWIgOGszQmUz/kanfgrfFZ4qiwxKIfT/ryl3N3Ewk5tqizmYtNXiqb7Bu/fDtNgu1kyxdFiAUJNur3iysg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@tailwindcss/node": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz", @@ -2629,6 +4723,22 @@ "@testing-library/dom": ">=7.21.4" } }, + "node_modules/@trickfilm400/rollup-plugin-off-main-thread": { + "version": "3.0.0-pre1", + "resolved": "https://registry.npmjs.org/@trickfilm400/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-3.0.0-pre1.tgz", + "integrity": "sha512-/67zpWDBLV+oYAEL682s1ktXL0HgqX76f6gaVGkGnVZlBbm1zd0v4Bz8MFF2GGhoX9rvfq3KSQHubFHwa6w6/Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "ejs": "^3.1.10", + "json5": "^2.2.3", + "magic-string": "^0.30.21", + "string.prototype.matchall": "^4.0.12" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@types/aria-query": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", @@ -2694,6 +4804,16 @@ "pg-types": "^2.2.0" } }, + "node_modules/@types/qrcode": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.6.tgz", + "integrity": "sha512-te7NQcV2BOvdj2b1hCAHzAoMNuj65kNBMz0KBaxM6c3VGBOhU0dURQKOtH8CFNI/dsKkwlv32p26qYQTWoB5bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/react": { "version": "19.2.18", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", @@ -2714,6 +4834,20 @@ "@types/react": "^19.2.0" } }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript/typescript-aix-ppc64": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", @@ -3132,13 +5266,42 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/acorn": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.19.0.tgz", + "integrity": "sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -3167,6 +5330,45 @@ "dequal": "^2.0.3" } }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", @@ -3177,6 +5379,114 @@ "node": ">=12" } }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", + "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", + "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8", + "core-js-compat": "^3.48.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", + "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.27", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.27.tgz", + "integrity": "sha512-ElY12DaROGuan+lMmZ8Cvo/ZUbXPe7Enc/9VU/b1T3Kp4dwytRcNdR8DoSJN5SNJT/CuvcCA0DHDVmMOCePdRQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/bidi-js": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.1.0.tgz", @@ -3187,6 +5497,53 @@ "require-from-string": "^2.0.2" } }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/browserslist": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.3.tgz", + "integrity": "sha512-1R4kiYKXGViqEN0CnoDrXc1StD9niAwu+j2dukWzrD4bJgsD4lDmEp0CRbc6E/vYJIfTHwPmwyaKtVSudICdPA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.26", + "caniuse-lite": "^1.0.30001813", + "electron-to-chromium": "^1.5.439", + "node-releases": "^2.0.57", + "update-browserslist-db": "^1.3.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3194,6 +5551,87 @@ "dev": true, "license": "MIT" }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001814", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001814.tgz", + "integrity": "sha512-/Uaf1lAzr59XcMpW0o96WoEfr+VXK2OX4U9AgFoiSHsVJ4HppnIFUjtYzsyDH2+tgANaQb2/oxYGwCPapN1FpA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, "node_modules/chai": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/chai/-/chai-6.3.0.tgz", @@ -3232,6 +5670,43 @@ "node": ">=20" } }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/concurrently": { "version": "10.0.5", "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-10.0.5.tgz", @@ -3257,6 +5732,13 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, "node_modules/cookie": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", @@ -3271,6 +5753,48 @@ "url": "https://opencollective.com/express" } }, + "node_modules/core-js-compat": { + "version": "3.50.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.50.0.tgz", + "integrity": "sha512-XGpFGbMLHwSt74YLTKho7Ib242qi6O8MSX+sRokV4oz7iKXvQWGYZthjIhjRGMxjzVkAubBO512dKGYcefmX3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.7" + }, + "engines": { + "node": ">=6.4.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/css-tree": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", @@ -3313,6 +5837,88 @@ "node": "^22.14.0 || >=24.0.0" } }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/decimal.js": { "version": "10.6.0", "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", @@ -3320,6 +5926,52 @@ "dev": true, "license": "MIT" }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -3340,6 +5992,13 @@ "node": ">=8" } }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", + "dev": true, + "license": "MIT" + }, "node_modules/dom-accessibility-api": { "version": "0.5.16", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", @@ -3977,6 +6636,44 @@ } } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.446", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.446.tgz", + "integrity": "sha512-kWlGMPHzuitCKx0O+MbY1ZGvQmP14JtckrnGjD4JsusTxh2cX9wu4bb4rOYZqLSvENjFFrHzlqY8kXhseucR/w==", + "dev": true, + "license": "ISC" + }, "node_modules/emoji-regex": { "version": "10.6.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", @@ -4011,6 +6708,114 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract-get": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-abstract-get/-/es-abstract-get-1.0.0.tgz", + "integrity": "sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.2", + "is-callable": "^1.2.7", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", @@ -4018,6 +6823,56 @@ "dev": true, "license": "MIT" }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.4.tgz", + "integrity": "sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-abstract-get": "^1.0.0", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "is-callable": "^1.2.7", + "is-date-object": "^1.1.0", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/esbuild": { "version": "0.28.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", @@ -4080,6 +6935,29 @@ "@types/estree": "^1.0.0" } }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eta": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-4.6.0.tgz", + "integrity": "sha512-lW6is4T1NFOYnmqGZIfvixqj7A7sSvScF+DN8EK6K58xI5MZ5UvYe0GjopxOXQtZvUn4eDdVuZ8XSoYWTMEKwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/bgub/eta?sponsor=1" + } + }, "node_modules/expect-type": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", @@ -4090,6 +6968,47 @@ "node": ">=12.0.0" } }, + "node_modules/fake-indexeddb": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/fake-indexeddb/-/fake-indexeddb-6.2.5.tgz", + "integrity": "sha512-CGnyrvbhPlWYMngksqrSSUT1BAVP49dZocrHuK0SvtR0D5TMs5wP0o3j7jexDJW01KSadjBp1M/71o/KR3nD1w==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -4108,6 +7027,109 @@ } } }, + "node_modules/filelist": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -4123,6 +7145,70 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.2.0.tgz", + "integrity": "sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2", + "hasown": "^2.0.4", + "is-callable": "^1.2.7", + "is-document.all": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -4146,6 +7232,70 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "dev": true, + "license": "ISC" + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-tsconfig": { "version": "4.14.3", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.3.tgz", @@ -4159,6 +7309,61 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/glob": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", + "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -4166,6 +7371,90 @@ "dev": true, "license": "ISC" }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hono": { "version": "4.13.13", "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.13.tgz", @@ -4188,6 +7477,13 @@ "node": "^22.13.0 || >=24.0.0" } }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "dev": true, + "license": "ISC" + }, "node_modules/indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", @@ -4198,6 +7494,278 @@ "node": ">=8" } }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.17.0.tgz", + "integrity": "sha512-J/vG0zBCbIKOQFfufSwyXdMrsohyJIUNkrnmo6WZGzoM7tr/lsbfW5b2BvisL6zsyMzK9UxV9L6c7AoFbyXHOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-document.all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-document.all/-/is-document.all-1.0.0.tgz", + "integrity": "sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -4205,6 +7773,222 @@ "dev": true, "license": "MIT" }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz", + "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^9.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jiti": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", @@ -4220,8 +8004,7 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/jsdom": { "version": "30.1.2", @@ -4263,6 +8046,72 @@ } } }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/lightningcss": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", @@ -4536,6 +8385,26 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" + }, "node_modules/lru-cache": { "version": "11.5.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", @@ -4577,6 +8446,16 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mdn-data": { "version": "2.27.1", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", @@ -4594,6 +8473,39 @@ "node": ">=4" } }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, "node_modules/nanoid": { "version": "3.3.18", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", @@ -4613,6 +8525,16 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/node-releases": { + "version": "2.0.57", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.57.tgz", + "integrity": "sha512-kQK9LGGFiHtrWiNhZtA7Qbw17AQz+dmsEKODRIVTXA9+e5MS/2gZEBhYJt13GrAz5/IOZKddH/0Z3TP/Zgo+yw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/nodemailer": { "version": "10.0.15", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-10.0.15.tgz", @@ -4622,6 +8544,50 @@ "node": ">=20.0.0" } }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/obug": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/obug/-/obug-2.2.1.tgz", @@ -4636,6 +8602,25 @@ "node": ">=12.20.0" } }, + "node_modules/own-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.2.tgz", + "integrity": "sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/oxlint": { "version": "1.81.0", "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.81.0.tgz", @@ -4685,6 +8670,52 @@ } } }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parse5": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", @@ -4698,6 +8729,50 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/pg": { "version": "8.23.1", "resolved": "https://registry.npmjs.org/pg/-/pg-8.23.1.tgz", @@ -4836,6 +8911,26 @@ "node": ">=20" } }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/postcss": { "version": "8.5.26", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", @@ -4904,6 +8999,19 @@ "node": ">=0.10.0" } }, + "node_modules/pretty-bytes": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz", + "integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", @@ -4930,6 +9038,146 @@ "node": ">=6" } }, + "node_modules/qrcode": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", + "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "dijkstrajs": "^1.0.1", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/qrcode/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/qrcode/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/qrcode/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/qrcode/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/qrcode/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/react": { "version": "19.2.8", "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", @@ -5015,6 +9263,118 @@ "node": ">=8" } }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.5.0.tgz", + "integrity": "sha512-1s+CxXjJ71i7LNVy8nYwg47XV4y6lAnOEhsMtSKq3WpmPfhl9LuKlTqKIn/3yUpE8lBz+W+TT88Bxyhnr0U4yw==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.3.0.tgz", + "integrity": "sha512-9ns8odR8e9q3otKeHj3DE80jZYKg6zVeZKE+zQmRKXFoVUcuiTGeO6iusDhPRoIQQPVPRvH+SfBhrTud4eczuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.5.3.tgz", + "integrity": "sha512-E8VgUoSK+LMQrLboDxavm76MTBGrQhx9RiNuomRmYnZ10Uw12HrI8fkxOOncktb2hBpzIZ9SV/347euQHG5z+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.5.0", + "regenerate-unicode-properties": "^10.3.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.4.tgz", + "integrity": "sha512-EWV80YgFaVgFrjGCAsV7oybp4GOxbls5RzBg8OB0nKEVXsBJR1JlV8Di1JhCROg3MzTfe1RI8yitIm1eOs68iA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -5025,6 +9385,35 @@ "node": ">=0.10.0" } }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true, + "license": "ISC" + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -5069,6 +9458,52 @@ "@rolldown/binding-win32-x64-msvc": "1.2.7" } }, + "node_modules/rollup": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.64.0.tgz", + "integrity": "sha512-gjA/kFeDfffII8COoPsvLPvE16hWDTEc1+0QKQNKUkuV8iJjqsC4xXs8/FzuL0v9EV39kuxTbAgcFoTRyy2TGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.64.0", + "@rollup/rollup-android-arm64": "4.64.0", + "@rollup/rollup-darwin-arm64": "4.64.0", + "@rollup/rollup-darwin-x64": "4.64.0", + "@rollup/rollup-freebsd-arm64": "4.64.0", + "@rollup/rollup-freebsd-x64": "4.64.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.64.0", + "@rollup/rollup-linux-arm-musleabihf": "4.64.0", + "@rollup/rollup-linux-arm64-gnu": "4.64.0", + "@rollup/rollup-linux-arm64-musl": "4.64.0", + "@rollup/rollup-linux-loong64-gnu": "4.64.0", + "@rollup/rollup-linux-loong64-musl": "4.64.0", + "@rollup/rollup-linux-ppc64-gnu": "4.64.0", + "@rollup/rollup-linux-ppc64-musl": "4.64.0", + "@rollup/rollup-linux-riscv64-gnu": "4.64.0", + "@rollup/rollup-linux-riscv64-musl": "4.64.0", + "@rollup/rollup-linux-s390x-gnu": "4.64.0", + "@rollup/rollup-linux-x64-gnu": "4.64.0", + "@rollup/rollup-linux-x64-musl": "4.64.0", + "@rollup/rollup-openbsd-x64": "4.64.0", + "@rollup/rollup-openharmony-arm64": "4.64.0", + "@rollup/rollup-win32-arm64-msvc": "4.64.0", + "@rollup/rollup-win32-ia32-msvc": "4.64.0", + "@rollup/rollup-win32-x64-gnu": "4.64.0", + "@rollup/rollup-win32-x64-msvc": "4.64.0", + "fsevents": "~2.3.2" + } + }, "node_modules/rxjs": { "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", @@ -5079,6 +9514,61 @@ "tslib": "^2.1.0" } }, + "node_modules/safe-array-concat": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", @@ -5099,6 +9589,33 @@ "dev": true, "license": "MIT" }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-javascript": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.1.2.tgz", + "integrity": "sha512-GL2BWwVa6JydKO6l/ljVgjAZF4QJ3S7dWDWi53s5GZT8PJzD2fNxi67HANQGKAqPrwEpL5ba7gUBGi0Ls/sEoQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, "node_modules/set-cookie-parser": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", @@ -5106,6 +9623,78 @@ "dev": true, "license": "MIT" }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/shell-quote": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.9.0.tgz", @@ -5119,6 +9708,105 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/smob": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.6.2.tgz", + "integrity": "sha512-RQsvleCbF8cVHEv+xuDGaA4pOizFqJ0GgjtMSRo6oP8pnN7WsigHgVGey6aILRBKv4W2YOMHLqbKdnB6hpB9fw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -5166,6 +9854,20 @@ "dev": true, "license": "MIT" }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", @@ -5184,6 +9886,109 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/string.prototype.matchall": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.1.0.tgz", + "integrity": "sha512-tHNHTxInrYLCga9O9YGxWA3G9/nnzQw8UGAyqGx3Ar1pSTTzIuM4woFSq4SowkXCjJIwq5sIiQvEfRI9tCH1qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.2", + "get-intrinsic": "^1.3.0", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.4", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.11.tgz", + "integrity": "sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-object-atoms": "^1.1.2", + "has-property-descriptors": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.10.tgz", + "integrity": "sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/strip-ansi": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", @@ -5213,6 +10018,16 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, + "node_modules/strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/strip-indent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", @@ -5239,6 +10054,19 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/tailwindcss": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", @@ -5260,6 +10088,54 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tempy": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", + "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.51.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.51.2.tgz", + "integrity": "sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/tinybench": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-6.2.0.tgz", @@ -5379,6 +10255,96 @@ "fsevents": "~2.3.3" } }, + "node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.5.tgz", + "integrity": "sha512-0FHJvLPqZ7KJzp17O13jfsAjsqazgrxBu2zEK95PmUz8lv2+GjRuxUInCr2Rk9Dms3ihN21zJ929ZO43yJ95QQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.9", + "for-each": "^0.3.5", + "gopd": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.8.tgz", + "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "for-each": "^0.3.5", + "gopd": "^1.2.0", + "is-typed-array": "^1.1.15", + "possible-typed-array-names": "^1.1.0", + "reflect.getprototypeof": "^1.0.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typescript": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", @@ -5414,6 +10380,25 @@ "@typescript/typescript-win32-x64": "7.0.2" } }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/undici": { "version": "8.11.2", "resolved": "https://registry.npmjs.org/undici/-/undici-8.11.2.tgz", @@ -5431,6 +10416,115 @@ "devOptional": true, "license": "MIT" }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz", + "integrity": "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/vite": { "version": "8.2.2", "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz", @@ -5509,6 +10603,37 @@ } } }, + "node_modules/vite-plugin-pwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-2.0.0.tgz", + "integrity": "sha512-6G9dsPKT9QKYpeTuTLJM28zZL3HsXUTUM/QUZBEgQk2jbfrPJDq2i8gTewAKqi1c9Mt6MiidrL4SFI+HthiQMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.6", + "pretty-bytes": "^6.1.1", + "tinyglobby": "^0.2.10", + "workbox-build": "^7.4.1", + "workbox-window": "^7.4.1" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vite-pwa/assets-generator": "^1.0.0 || ^2.0.0", + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "workbox-build": "^7.4.1", + "workbox-window": "^7.4.1" + }, + "peerDependenciesMeta": { + "@vite-pwa/assets-generator": { + "optional": true + } + } + }, "node_modules/vitest": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/vitest/-/vitest-5.0.3.tgz", @@ -5650,6 +10775,118 @@ "node": "^22.14.0 || >=24.0.0" } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/which-typed-array": { + "version": "1.1.24", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.24.tgz", + "integrity": "sha512-wk4Mf4pR5mRP7eYuuTBCIQ9d0ud2Fv2jRLQpfgnRjbOxAFHmjKFValgTpitVKzJJS8ajnYQV2Du1SZ8j6b/EUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/why-is-node-running": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-3.2.1.tgz", @@ -5663,6 +10900,236 @@ "node": ">=20.11" } }, + "node_modules/workbox-background-sync": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-7.4.1.tgz", + "integrity": "sha512-HhT7KE8tOWDm02wRNshXUnUPofMlhenF2DBdUnDPOubhizzPeItkYTmAB6td1Z2cjYPa98vzEiPLEuzn5hN66g==", + "dev": true, + "license": "MIT", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-broadcast-update": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-7.4.1.tgz", + "integrity": "sha512-uAlgslKLvbQY+suirIdnBCSYrcgBhjp81Nj4l1lj/Jmj0MJO2CJERnCJjT0GFVwmReV0N+zs78K6gqd5gr9/+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-build": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-7.4.1.tgz", + "integrity": "sha512-SDhxIvEAde9Gy/5w4Yo1Jh/M49Z0qE3q0oteyE8zGq0DScxFqVBcCtIXFuLtmtxRQZCMbf0prco4VyEu3KBQuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apideck/better-ajv-errors": "^0.3.1", + "@babel/core": "^7.24.4", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.2", + "@rollup/plugin-babel": "^6.1.0", + "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-replace": "^6.0.3", + "@rollup/plugin-terser": "^1.0.0", + "@trickfilm400/rollup-plugin-off-main-thread": "^3.0.0-pre1", + "ajv": "^8.6.0", + "common-tags": "^1.8.0", + "eta": "^4.5.1", + "fast-json-stable-stringify": "^2.1.0", + "fs-extra": "^9.0.1", + "glob": "^11.0.1", + "pretty-bytes": "^5.3.0", + "rollup": "^4.53.3", + "source-map": "^0.8.0-beta.0", + "stringify-object": "^3.3.0", + "strip-comments": "^2.0.1", + "tempy": "^0.6.0", + "upath": "^1.2.0", + "workbox-background-sync": "7.4.1", + "workbox-broadcast-update": "7.4.1", + "workbox-cacheable-response": "7.4.1", + "workbox-core": "7.4.1", + "workbox-expiration": "7.4.1", + "workbox-google-analytics": "7.4.1", + "workbox-navigation-preload": "7.4.1", + "workbox-precaching": "7.4.1", + "workbox-range-requests": "7.4.1", + "workbox-recipes": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1", + "workbox-streams": "7.4.1", + "workbox-sw": "7.4.1", + "workbox-window": "7.4.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/workbox-build/node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/workbox-build/node_modules/source-map": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0.tgz", + "integrity": "sha512-d8EqvL+k/SOXCreS/SUzg2ciyHqBBLcN/yuRjFsbvVhHTE2pgei7oAhmPM7kWFbkX6OSMQfUq4KbkF3au9lhYQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/workbox-cacheable-response": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-7.4.1.tgz", + "integrity": "sha512-8xaFoJdDc2OjrlbbL3gEeBO1WKcMwRqwLRupgqahYXu75yXajPLuwrbXMrIGZuWYXrQwk0xDjOxZ/ujCy/oJYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-core": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-7.4.1.tgz", + "integrity": "sha512-DT+vu46eh/2vRsSHTY4Xmc32Z1rr9PRlQUXr1Dx30ZuXRWwOsvZgGgcwxcasubQLQmbTNYZjv44LkBAQ4tT5tQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/workbox-expiration": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-7.4.1.tgz", + "integrity": "sha512-lRKUF7b+OGbeXkQk1s6MHXOa3d7Xxf7Of31W6c6hCfipfIyrtdWZ89stq21AHZMaoG7VNFoHply4Ox+rU31TWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-google-analytics": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-7.4.1.tgz", + "integrity": "sha512-Mks1JwLEt++ZAkF6sS1OpSh9RtAMIsiDgRpK+codiHGIPXeaUOgi4cPc3GFadUl8V5QPeypEk8Oxgl3HlwVzHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-background-sync": "7.4.1", + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" + } + }, + "node_modules/workbox-navigation-preload": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-7.4.1.tgz", + "integrity": "sha512-C4KVsjPcYKJOhr631AxR9XoG2rLF3QiTk5aMv36MXOjtWvm8axwNFAtKUPGsWUwLXXAMgYM1En7fsvndaXeXRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-precaching": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-7.4.1.tgz", + "integrity": "sha512-cdr/9qByww7yzEp7zg/qI4ukUrrNjQLgN+ONQRpjy/VqGQXwkgHwr00KksGJK8v0VifwDXBb8a4cWNZH71jn3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" + } + }, + "node_modules/workbox-range-requests": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-7.4.1.tgz", + "integrity": "sha512-7i2oxAUE82gHdAJBCAQ04JzNOdRPqzuOzGfoUyJpFSmeqBNYGPrAH8GPoPjUQTfp+NycwrD2H68VtuF8qxv0vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-recipes": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-7.4.1.tgz", + "integrity": "sha512-gnbVfmV4/TtmQaM4x9AtuXhcdstJsep3XMVeztOrQVPT+R6+6DeBjGTCQ7fFCXm+4GEHUA5VEBTyi5+4gWGeog==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-cacheable-response": "7.4.1", + "workbox-core": "7.4.1", + "workbox-expiration": "7.4.1", + "workbox-precaching": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" + } + }, + "node_modules/workbox-routing": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-7.4.1.tgz", + "integrity": "sha512-yubJGErZOusuidAenaL5ypfhQOa7urxP/f8E0ws7FPb4039RiWXUWBAyUkmUoOL/BcQGen3h0J8872d51IYxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-strategies": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-7.4.1.tgz", + "integrity": "sha512-GZxpaw9NbmOelj7667uZ2kpk5BFpOGbO4X0qjwh5ls8XQ8C+Lha5LQchTiUzsTFSS+NlUpftYAyOVXvQUrcqOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-streams": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-7.4.1.tgz", + "integrity": "sha512-HWWtraKUbJknd9kgqGcpQ3G114HOPYvqs8HaJMDs2ebLNAimDkVDaWfAXE6Ybl+m8U6KsCE6pWyLYuigWmnAXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1" + } + }, + "node_modules/workbox-sw": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-7.4.1.tgz", + "integrity": "sha512-fez5f2DUlDJWTFYkCWQpY10N8gtztd849NswCbVFk0QlcSM4HT5A8x4g4ii650yem4I8tHY0R7JZahwp3ltIPw==", + "dev": true, + "license": "MIT" + }, + "node_modules/workbox-window": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-7.4.1.tgz", + "integrity": "sha512-notZDH2u8VXaqyuD7xaqIfEFi6SRM4SUSd7ewe9PDsVqADuepxX2ZMY3uvuZGxzY5ZOsGC/vD3A/3smFtJt4/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/trusted-types": "^2.0.2", + "workbox-core": "7.4.1" + } + }, "node_modules/wrap-ansi": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", @@ -5730,6 +11197,13 @@ "node": ">=10" } }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, "node_modules/yargs": { "version": "18.0.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", diff --git a/package.json b/package.json index 1e8a645..b8b41e9 100644 --- a/package.json +++ b/package.json @@ -47,20 +47,25 @@ "@types/node": "^26.6.4", "@types/nodemailer": "^8.0.2", "@types/pg": "^8.23.1", + "@types/qrcode": "^1.5.6", "@types/react": "^19.2.18", "@types/react-dom": "^19.2.4", "@vitejs/plugin-react": "^6.1.0", "concurrently": "^10.0.5", "drizzle-kit": "^0.31.11", + "fake-indexeddb": "^6.2.5", "jsdom": "^30.1.2", "lucide-react": "^1.39.0", "oxlint": "^1.79.0", + "qrcode": "^1.5.4", "react": "^19.2.8", "react-dom": "^19.2.8", "react-router-dom": "^7.18.3", "tailwindcss": "^4.3.3", "typescript": "^7.0.2", "vite": "^8.2.2", - "vitest": "^5.0.3" + "vite-plugin-pwa": "^2.0.0", + "vitest": "^5.0.3", + "workbox-window": "^7.4.1" } } diff --git a/public/icons/apple-touch-icon.png b/public/icons/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4ff7fb5ef7b5368b7b163c2ab519f07c81c5e8e8 GIT binary patch literal 3403 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 N=C|&c)EGfy{{zoCk6-`* literal 0 HcmV?d00001 diff --git a/public/icons/icon-192.png b/public/icons/icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..4feb877a8a9eefad20a5b03c360959ead5b064ad GIT binary patch literal 5982 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 M07*qoM6N<$f{Em>)&Kwi literal 0 HcmV?d00001 diff --git a/public/icons/icon-512.png b/public/icons/icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..e7a74075e8f98dc696114991bfc53a4a3192f653 GIT binary patch literal 17162 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 w ` + + ` + +// Regular icon: rounded tile. Maskable: full-bleed square with the mark inside the safe zone. +const regular = `${shield(2.2)}` +const maskable = `${shield(2.4)}` + +const outputs = [ + ['public/icons/icon-192.png', regular, 192], + ['public/icons/icon-512.png', regular, 512], + ['public/icons/maskable-512.png', maskable, 512], + ['public/icons/apple-touch-icon.png', maskable, 180], +] + +const browser = await chromium.launch() +const page = await browser.newPage() +for (const [path, svg, size] of outputs) { + await page.setViewportSize({ width: size, height: size }) + await page.setContent(``) + await page.locator('img').screenshot({ path, omitBackground: true }) + console.log('wrote', path) +} +await browser.close() diff --git a/server/app.ts b/server/app.ts index f8e8877..2ee778e 100644 --- a/server/app.ts +++ b/server/app.ts @@ -11,6 +11,7 @@ import { actionRoutes } from './routes/actions.ts' import { attachmentRoutes } from './routes/attachments.ts' import { authRoutes } from './routes/auth.ts' import { incidentRoutes } from './routes/incidents.ts' +import { kioskAdminRoutes, kioskPublicRoutes } from './routes/kiosks.ts' import { rootCauseRoutes } from './routes/root-causes.ts' import { setupRoutes } from './routes/setup.ts' import { areaRoutes, siteRoutes } from './routes/sites.ts' @@ -54,6 +55,8 @@ export function createApp({ db, config, notifier, storage }: AppDeps) { app.route('/api/actions', actionRoutes) app.route('/api/attachments', attachmentRoutes) app.route('/api/stats', statsRoutes) + app.route('/api/kiosks', kioskAdminRoutes) + app.route('/api/kiosk', kioskPublicRoutes()) app.all('/api/*', (c) => c.json({ error: 'Not found' }, 404)) app.onError((error, c) => { diff --git a/server/db/migrations/0002_kiosks_and_offline.sql b/server/db/migrations/0002_kiosks_and_offline.sql new file mode 100644 index 0000000..2965238 --- /dev/null +++ b/server/db/migrations/0002_kiosks_and_offline.sql @@ -0,0 +1,24 @@ +CREATE TYPE "public"."report_channel" AS ENUM('web', 'kiosk');--> statement-breakpoint +CREATE TABLE "kiosks" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "organization_id" uuid NOT NULL, + "name" text NOT NULL, + "token" text NOT NULL, + "site_id" uuid, + "created_by_id" uuid, + "last_used_at" timestamp with time zone, + "revoked_at" timestamp with time zone, + "created_at" timestamp with time zone DEFAULT now() NOT NULL +); +--> statement-breakpoint +ALTER TABLE "incidents" ADD COLUMN "reporter_name" text;--> statement-breakpoint +ALTER TABLE "incidents" ADD COLUMN "channel" "report_channel" DEFAULT 'web' NOT NULL;--> statement-breakpoint +ALTER TABLE "incidents" ADD COLUMN "kiosk_id" uuid;--> statement-breakpoint +ALTER TABLE "incidents" ADD COLUMN "client_id" uuid;--> statement-breakpoint +ALTER TABLE "kiosks" ADD CONSTRAINT "kiosks_organization_id_organizations_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "kiosks" ADD CONSTRAINT "kiosks_site_id_sites_id_fk" FOREIGN KEY ("site_id") REFERENCES "public"."sites"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "kiosks" ADD CONSTRAINT "kiosks_created_by_id_users_id_fk" FOREIGN KEY ("created_by_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint +CREATE UNIQUE INDEX "kiosks_token_unique" ON "kiosks" USING btree ("token");--> statement-breakpoint +CREATE INDEX "kiosks_organization_idx" ON "kiosks" USING btree ("organization_id");--> statement-breakpoint +ALTER TABLE "incidents" ADD CONSTRAINT "incidents_kiosk_id_kiosks_id_fk" FOREIGN KEY ("kiosk_id") REFERENCES "public"."kiosks"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint +CREATE UNIQUE INDEX "incidents_organization_client_id_unique" ON "incidents" USING btree ("organization_id","client_id"); \ No newline at end of file diff --git a/server/db/migrations/meta/0002_snapshot.json b/server/db/migrations/meta/0002_snapshot.json new file mode 100644 index 0000000..e100ce9 --- /dev/null +++ b/server/db/migrations/meta/0002_snapshot.json @@ -0,0 +1,2131 @@ +{ + "id": "9f956116-7800-4428-8fdd-c21f012e29b7", + "prevId": "06635c3f-6dbf-4fb2-9f0d-54c5f9227434", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.areas": { + "name": "areas", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "site_id": { + "name": "site_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "area_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'area'" + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "areas_site_idx": { + "name": "areas_site_idx", + "columns": [ + { + "expression": "site_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "areas_parent_idx": { + "name": "areas_parent_idx", + "columns": [ + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "areas_site_id_sites_id_fk": { + "name": "areas_site_id_sites_id_fk", + "tableFrom": "areas", + "tableTo": "sites", + "columnsFrom": [ + "site_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "areas_parent_id_areas_id_fk": { + "name": "areas_parent_id_areas_id_fk", + "tableFrom": "areas", + "tableTo": "areas", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.attachments": { + "name": "attachments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "incident_id": { + "name": "incident_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "file_name": { + "name": "file_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "size_bytes": { + "name": "size_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "storage_key": { + "name": "storage_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uploaded_by_id": { + "name": "uploaded_by_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "attachments_incident_idx": { + "name": "attachments_incident_idx", + "columns": [ + { + "expression": "incident_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "attachments_incident_id_incidents_id_fk": { + "name": "attachments_incident_id_incidents_id_fk", + "tableFrom": "attachments", + "tableTo": "incidents", + "columnsFrom": [ + "incident_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "attachments_uploaded_by_id_users_id_fk": { + "name": "attachments_uploaded_by_id_users_id_fk", + "tableFrom": "attachments", + "tableTo": "users", + "columnsFrom": [ + "uploaded_by_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "attachments_storageKey_unique": { + "name": "attachments_storageKey_unique", + "nullsNotDistinct": false, + "columns": [ + "storage_key" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_log": { + "name": "audit_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "actor_id": { + "name": "actor_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "entity_type": { + "name": "entity_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_id": { + "name": "entity_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "changes": { + "name": "changes", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "audit_log_entity_idx": { + "name": "audit_log_entity_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "audit_log_organization_id_organizations_id_fk": { + "name": "audit_log_organization_id_organizations_id_fk", + "tableFrom": "audit_log", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "audit_log_actor_id_users_id_fk": { + "name": "audit_log_actor_id_users_id_fk", + "tableFrom": "audit_log", + "tableTo": "users", + "columnsFrom": [ + "actor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auth_tokens": { + "name": "auth_tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "purpose": { + "name": "purpose", + "type": "auth_token_purpose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "used_at": { + "name": "used_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "auth_tokens_user_idx": { + "name": "auth_tokens_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "auth_tokens_user_id_users_id_fk": { + "name": "auth_tokens_user_id_users_id_fk", + "tableFrom": "auth_tokens", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.comments": { + "name": "comments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "incident_id": { + "name": "incident_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "author_id": { + "name": "author_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "comments_incident_idx": { + "name": "comments_incident_idx", + "columns": [ + { + "expression": "incident_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "comments_incident_id_incidents_id_fk": { + "name": "comments_incident_id_incidents_id_fk", + "tableFrom": "comments", + "tableTo": "incidents", + "columnsFrom": [ + "incident_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "comments_author_id_users_id_fk": { + "name": "comments_author_id_users_id_fk", + "tableFrom": "comments", + "tableTo": "users", + "columnsFrom": [ + "author_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.corrective_actions": { + "name": "corrective_actions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "incident_id": { + "name": "incident_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "root_cause_id": { + "name": "root_cause_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "kind": { + "name": "kind", + "type": "action_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'corrective'" + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "assignee_id": { + "name": "assignee_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "due_date": { + "name": "due_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "action_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'open'" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "verified_by_id": { + "name": "verified_by_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "verified_at": { + "name": "verified_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "reminder_sent_on": { + "name": "reminder_sent_on", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "corrective_actions_incident_idx": { + "name": "corrective_actions_incident_idx", + "columns": [ + { + "expression": "incident_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "corrective_actions_assignee_status_idx": { + "name": "corrective_actions_assignee_status_idx", + "columns": [ + { + "expression": "assignee_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "corrective_actions_incident_id_incidents_id_fk": { + "name": "corrective_actions_incident_id_incidents_id_fk", + "tableFrom": "corrective_actions", + "tableTo": "incidents", + "columnsFrom": [ + "incident_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "corrective_actions_root_cause_id_root_causes_id_fk": { + "name": "corrective_actions_root_cause_id_root_causes_id_fk", + "tableFrom": "corrective_actions", + "tableTo": "root_causes", + "columnsFrom": [ + "root_cause_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "corrective_actions_assignee_id_users_id_fk": { + "name": "corrective_actions_assignee_id_users_id_fk", + "tableFrom": "corrective_actions", + "tableTo": "users", + "columnsFrom": [ + "assignee_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "corrective_actions_verified_by_id_users_id_fk": { + "name": "corrective_actions_verified_by_id_users_id_fk", + "tableFrom": "corrective_actions", + "tableTo": "users", + "columnsFrom": [ + "verified_by_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hours_worked": { + "name": "hours_worked", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "site_id": { + "name": "site_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "month": { + "name": "month", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "hours": { + "name": "hours", + "type": "numeric(12, 2)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "hours_worked_site_month_unique": { + "name": "hours_worked_site_month_unique", + "columns": [ + { + "expression": "site_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "month", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "hours_worked_site_id_sites_id_fk": { + "name": "hours_worked_site_id_sites_id_fk", + "tableFrom": "hours_worked", + "tableTo": "sites", + "columnsFrom": [ + "site_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.incident_counters": { + "name": "incident_counters", + "schema": "", + "columns": { + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "last_number": { + "name": "last_number", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": { + "incident_counters_organization_id_organizations_id_fk": { + "name": "incident_counters_organization_id_organizations_id_fk", + "tableFrom": "incident_counters", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.incidents": { + "name": "incidents", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "number": { + "name": "number", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "incident_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "severity": { + "name": "severity", + "type": "severity", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "incident_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'reported'" + }, + "occurred_at": { + "name": "occurred_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "site_id": { + "name": "site_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "area_id": { + "name": "area_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "location_detail": { + "name": "location_detail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "immediate_action": { + "name": "immediate_action", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "reporter_id": { + "name": "reporter_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "anonymous": { + "name": "anonymous", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "reporter_name": { + "name": "reporter_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "channel": { + "name": "channel", + "type": "report_channel", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'web'" + }, + "kiosk_id": { + "name": "kiosk_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "client_id": { + "name": "client_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "closed_at": { + "name": "closed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "incidents_organization_number_unique": { + "name": "incidents_organization_number_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "number", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "incidents_organization_client_id_unique": { + "name": "incidents_organization_client_id_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "client_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "incidents_organization_occurred_idx": { + "name": "incidents_organization_occurred_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "occurred_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "incidents_organization_status_idx": { + "name": "incidents_organization_status_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "incidents_reporter_idx": { + "name": "incidents_reporter_idx", + "columns": [ + { + "expression": "reporter_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "incidents_organization_id_organizations_id_fk": { + "name": "incidents_organization_id_organizations_id_fk", + "tableFrom": "incidents", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "incidents_site_id_sites_id_fk": { + "name": "incidents_site_id_sites_id_fk", + "tableFrom": "incidents", + "tableTo": "sites", + "columnsFrom": [ + "site_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "incidents_area_id_areas_id_fk": { + "name": "incidents_area_id_areas_id_fk", + "tableFrom": "incidents", + "tableTo": "areas", + "columnsFrom": [ + "area_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "incidents_reporter_id_users_id_fk": { + "name": "incidents_reporter_id_users_id_fk", + "tableFrom": "incidents", + "tableTo": "users", + "columnsFrom": [ + "reporter_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "incidents_kiosk_id_kiosks_id_fk": { + "name": "incidents_kiosk_id_kiosks_id_fk", + "tableFrom": "incidents", + "tableTo": "kiosks", + "columnsFrom": [ + "kiosk_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.injured_persons": { + "name": "injured_persons", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "incident_id": { + "name": "incident_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "job_title": { + "name": "job_title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "employment_type": { + "name": "employment_type", + "type": "employment_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'employee'" + }, + "body_part": { + "name": "body_part", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "nature_of_injury": { + "name": "nature_of_injury", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "treatment": { + "name": "treatment", + "type": "treatment_level", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "days_away": { + "name": "days_away", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "days_restricted": { + "name": "days_restricted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "privacy_case": { + "name": "privacy_case", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "injured_persons_incident_idx": { + "name": "injured_persons_incident_idx", + "columns": [ + { + "expression": "incident_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "injured_persons_incident_id_incidents_id_fk": { + "name": "injured_persons_incident_id_incidents_id_fk", + "tableFrom": "injured_persons", + "tableTo": "incidents", + "columnsFrom": [ + "incident_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "injured_persons_user_id_users_id_fk": { + "name": "injured_persons_user_id_users_id_fk", + "tableFrom": "injured_persons", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.investigations": { + "name": "investigations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "incident_id": { + "name": "incident_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "lead_id": { + "name": "lead_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "method": { + "name": "method", + "type": "rca_method", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'five_whys'" + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "investigations_incident_id_incidents_id_fk": { + "name": "investigations_incident_id_incidents_id_fk", + "tableFrom": "investigations", + "tableTo": "incidents", + "columnsFrom": [ + "incident_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "investigations_lead_id_users_id_fk": { + "name": "investigations_lead_id_users_id_fk", + "tableFrom": "investigations", + "tableTo": "users", + "columnsFrom": [ + "lead_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "investigations_incidentId_unique": { + "name": "investigations_incidentId_unique", + "nullsNotDistinct": false, + "columns": [ + "incident_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.kiosks": { + "name": "kiosks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "site_id": { + "name": "site_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_by_id": { + "name": "created_by_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "kiosks_token_unique": { + "name": "kiosks_token_unique", + "columns": [ + { + "expression": "token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kiosks_organization_idx": { + "name": "kiosks_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "kiosks_organization_id_organizations_id_fk": { + "name": "kiosks_organization_id_organizations_id_fk", + "tableFrom": "kiosks", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "kiosks_site_id_sites_id_fk": { + "name": "kiosks_site_id_sites_id_fk", + "tableFrom": "kiosks", + "tableTo": "sites", + "columnsFrom": [ + "site_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "kiosks_created_by_id_users_id_fk": { + "name": "kiosks_created_by_id_users_id_fk", + "tableFrom": "kiosks", + "tableTo": "users", + "columnsFrom": [ + "created_by_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organizations": { + "name": "organizations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.root_causes": { + "name": "root_causes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "investigation_id": { + "name": "investigation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "root_cause_category", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "whys": { + "name": "whys", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "root_causes_investigation_idx": { + "name": "root_causes_investigation_idx", + "columns": [ + { + "expression": "investigation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "root_causes_investigation_id_investigations_id_fk": { + "name": "root_causes_investigation_id_investigations_id_fk", + "tableFrom": "root_causes", + "tableTo": "investigations", + "columnsFrom": [ + "investigation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sessions": { + "name": "sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "sessions_user_idx": { + "name": "sessions_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "sessions_user_id_users_id_fk": { + "name": "sessions_user_id_users_id_fk", + "tableFrom": "sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sites": { + "name": "sites", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'UTC'" + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "sites_organization_name_unique": { + "name": "sites_organization_name_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "sites_organization_id_organizations_id_fk": { + "name": "sites_organization_id_organizations_id_fk", + "tableFrom": "sites", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'reporter'" + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_login_at": { + "name": "last_login_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "users_email_unique": { + "name": "users_email_unique", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "users_organization_idx": { + "name": "users_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "users_organization_id_organizations_id_fk": { + "name": "users_organization_id_organizations_id_fk", + "tableFrom": "users", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.action_kind": { + "name": "action_kind", + "schema": "public", + "values": [ + "corrective", + "preventive" + ] + }, + "public.action_status": { + "name": "action_status", + "schema": "public", + "values": [ + "open", + "in_progress", + "done", + "verified", + "cancelled" + ] + }, + "public.area_kind": { + "name": "area_kind", + "schema": "public", + "values": [ + "building", + "area", + "line", + "other" + ] + }, + "public.auth_token_purpose": { + "name": "auth_token_purpose", + "schema": "public", + "values": [ + "magic_link", + "password_reset" + ] + }, + "public.employment_type": { + "name": "employment_type", + "schema": "public", + "values": [ + "employee", + "temporary", + "contractor", + "visitor" + ] + }, + "public.incident_status": { + "name": "incident_status", + "schema": "public", + "values": [ + "reported", + "triage", + "investigation", + "actions", + "verification", + "closed" + ] + }, + "public.incident_type": { + "name": "incident_type", + "schema": "public", + "values": [ + "near_miss", + "hazard", + "injury", + "illness", + "property_damage", + "environmental" + ] + }, + "public.rca_method": { + "name": "rca_method", + "schema": "public", + "values": [ + "five_whys", + "fishbone", + "other" + ] + }, + "public.report_channel": { + "name": "report_channel", + "schema": "public", + "values": [ + "web", + "kiosk" + ] + }, + "public.role": { + "name": "role", + "schema": "public", + "values": [ + "reporter", + "supervisor", + "safety_manager", + "admin" + ] + }, + "public.root_cause_category": { + "name": "root_cause_category", + "schema": "public", + "values": [ + "people", + "process", + "equipment", + "materials", + "environment", + "management" + ] + }, + "public.severity": { + "name": "severity", + "schema": "public", + "values": [ + "low", + "medium", + "high", + "critical" + ] + }, + "public.treatment_level": { + "name": "treatment_level", + "schema": "public", + "values": [ + "none", + "first_aid", + "medical_treatment", + "hospitalized", + "fatality" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/server/db/migrations/meta/_journal.json b/server/db/migrations/meta/_journal.json index 2fa122c..ddc781c 100644 --- a/server/db/migrations/meta/_journal.json +++ b/server/db/migrations/meta/_journal.json @@ -15,6 +15,13 @@ "when": 1791309275942, "tag": "0001_workflow_and_email", "breakpoints": true + }, + { + "idx": 2, + "version": "7", + "when": 1791310953907, + "tag": "0002_kiosks_and_offline", + "breakpoints": true } ] } \ No newline at end of file diff --git a/server/db/schema.ts b/server/db/schema.ts index 2ef99cf..c75e625 100644 --- a/server/db/schema.ts +++ b/server/db/schema.ts @@ -13,6 +13,7 @@ export const rootCauseCategoryEnum = pgEnum('root_cause_category', vocab.rootCau export const actionKindEnum = pgEnum('action_kind', vocab.actionKinds) export const actionStatusEnum = pgEnum('action_status', vocab.actionStatuses) export const authTokenPurposeEnum = pgEnum('auth_token_purpose', ['magic_link', 'password_reset']) +export const reportChannelEnum = pgEnum('report_channel', ['web', 'kiosk']) const id = () => uuid().primaryKey().defaultRandom() const timestamptz = () => timestamp({ withTimezone: true }) @@ -115,6 +116,29 @@ export const areas = pgTable( (t) => [index('areas_site_idx').on(t.siteId), index('areas_parent_idx').on(t.parentId)], ) +/** + * Reporting links let people without accounts file reports: on a shared kiosk tablet, or by scanning + * a QR code. The token only allows creating reports, so it is stored as-is to let admins reprint QR codes. + */ +export const kiosks = pgTable( + 'kiosks', + { + id: id(), + organizationId: uuid() + .notNull() + .references(() => organizations.id), + name: text().notNull(), + token: text().notNull(), + /** Limits the link to one site; null allows any. */ + siteId: uuid().references(() => sites.id, { onDelete: 'set null' }), + createdById: uuid().references(() => users.id, { onDelete: 'set null' }), + lastUsedAt: timestamptz(), + revokedAt: timestamptz(), + createdAt: createdAt(), + }, + (t) => [uniqueIndex('kiosks_token_unique').on(t.token), index('kiosks_organization_idx').on(t.organizationId)], +) + /** Per-organization counter for gap-free, human-friendly incident numbers. */ export const incidentCounters = pgTable('incident_counters', { organizationId: uuid() @@ -146,12 +170,19 @@ export const incidents = pgTable( /** Null when reported anonymously. */ reporterId: uuid().references(() => users.id, { onDelete: 'set null' }), anonymous: boolean().notNull().default(false), + /** Name typed by someone reporting without an account (kiosk/QR). */ + reporterName: text(), + channel: reportChannelEnum().notNull().default('web'), + kioskId: uuid().references(() => kiosks.id, { onDelete: 'set null' }), + /** Generated on the reporting device so retries after a lost response don't create duplicates. */ + clientId: uuid(), closedAt: timestamptz(), createdAt: createdAt(), updatedAt: updatedAt(), }, (t) => [ uniqueIndex('incidents_organization_number_unique').on(t.organizationId, t.number), + uniqueIndex('incidents_organization_client_id_unique').on(t.organizationId, t.clientId), index('incidents_organization_occurred_idx').on(t.organizationId, t.occurredAt), index('incidents_organization_status_idx').on(t.organizationId, t.status), index('incidents_reporter_idx').on(t.reporterId), diff --git a/server/lib/attachments.ts b/server/lib/attachments.ts new file mode 100644 index 0000000..c05dbd5 --- /dev/null +++ b/server/lib/attachments.ts @@ -0,0 +1,39 @@ +import { count, eq } from 'drizzle-orm' +import type { Config } from '../config.ts' +import type { Db } from '../db/client.ts' +import { attachments } from '../db/schema.ts' +import type { FileStorage } from '../storage.ts' +import { detectFileType } from './file-type.ts' +import { fail } from './http.ts' + +export const MAX_ATTACHMENTS_PER_INCIDENT = 20 + +/** Validates and stores one uploaded file against an incident. */ +export async function saveAttachment( + { db, storage, config }: { db: Db; storage: FileStorage; config: Config }, + incidentId: string, + file: unknown, + uploadedById: string | null, +) { + if (!(file instanceof File)) throw fail(400, 'Attach a file in the "file" field') + if (file.size > config.maxUploadBytes) throw fail(413, `Files can be at most ${Math.round(config.maxUploadBytes / 1024 / 1024)} MB`) + const [{ existing }] = await db.select({ existing: count() }).from(attachments).where(eq(attachments.incidentId, incidentId)) + if (existing >= MAX_ATTACHMENTS_PER_INCIDENT) throw fail(409, `An incident can have at most ${MAX_ATTACHMENTS_PER_INCIDENT} attachments`) + + const data = new Uint8Array(await file.arrayBuffer()) + const type = detectFileType(data) + if (!type) throw fail(400, 'Only photos (JPEG, PNG, WebP, GIF, HEIC) and PDFs can be attached') + + const storageKey = await storage.save(data, type.extension) + const fileName = (file.name || `attachment.${type.extension}`).replace(/[\r\n"\\/]/g, '_').slice(0, 200) + try { + const [row] = await db + .insert(attachments) + .values({ incidentId, fileName, contentType: type.contentType, sizeBytes: data.byteLength, storageKey, uploadedById }) + .returning() + return row + } catch (error) { + await storage.remove(storageKey) + throw error + } +} diff --git a/server/lib/incidents.ts b/server/lib/incidents.ts index ce01d1e..f9c2ed4 100644 --- a/server/lib/incidents.ts +++ b/server/lib/incidents.ts @@ -6,7 +6,7 @@ import { incidentReference } from '../../shared/format.ts' import { availableTransitions } from '../../shared/workflow.ts' import type { SessionUser } from '../auth/sessions.ts' import type { Db } from '../db/client.ts' -import { areas, attachments, correctiveActions, incidents, investigations, rootCauses, sites, users } from '../db/schema.ts' +import { areas, attachments, correctiveActions, incidents, investigations, kiosks, rootCauses, sites, users } from '../db/schema.ts' import { audit } from './audit.ts' import { iso, localDate } from './dates.ts' import { fail } from './http.ts' @@ -15,16 +15,17 @@ const reporters = alias(users, 'reporter') export function selectIncidents(db: Db) { return db - .select({ incident: incidents, siteName: sites.name, areaName: areas.name, reporterName: reporters.name }) + .select({ incident: incidents, siteName: sites.name, areaName: areas.name, reporterName: reporters.name, kioskName: kiosks.name }) .from(incidents) .innerJoin(sites, eq(sites.id, incidents.siteId)) .leftJoin(areas, eq(areas.id, incidents.areaId)) .leftJoin(reporters, eq(reporters.id, incidents.reporterId)) + .leftJoin(kiosks, eq(kiosks.id, incidents.kioskId)) } type IncidentRow = Awaited['execute']>>[number] -export function toIncident({ incident, siteName, areaName, reporterName }: IncidentRow): Incident { +export function toIncident({ incident, siteName, areaName, reporterName, kioskName }: IncidentRow): Incident { return { id: incident.id, number: incident.number, @@ -44,6 +45,9 @@ export function toIncident({ incident, siteName, areaName, reporterName }: Incid immediateAction: incident.immediateAction, anonymous: incident.anonymous, reporter: incident.reporterId ? { id: incident.reporterId, name: reporterName ?? '' } : null, + reporterName: incident.reporterName, + channel: incident.channel, + kiosk: incident.kioskId ? { id: incident.kioskId, name: kioskName ?? '' } : null, } } diff --git a/server/lib/reporting.ts b/server/lib/reporting.ts new file mode 100644 index 0000000..072580c --- /dev/null +++ b/server/lib/reporting.ts @@ -0,0 +1,115 @@ +import { and, eq, isNull, sql } from 'drizzle-orm' +import type { IncidentType, Severity } from '../../shared/enums.ts' +import type { SessionUser } from '../auth/sessions.ts' +import { isUniqueViolation, type Db } from '../db/client.ts' +import { areas, incidentCounters, incidents, sites } from '../db/schema.ts' +import type { Notifier } from '../notifications.ts' +import { fail } from './http.ts' +import { auditIncident } from './incidents.ts' + +/** Reports may be dated slightly ahead to absorb clock differences between devices. */ +const MAX_CLOCK_SKEW_MS = 5 * 60 * 1000 + +export function parseOccurredAt(value: string): Date { + const date = new Date(value) + if (date.getTime() > Date.now() + MAX_CLOCK_SKEW_MS) throw fail(400, 'Occurrence time cannot be in the future') + return date +} + +export async function assertLocation(db: Db, organizationId: string, siteId: string, areaId: string | null | undefined) { + const [site] = await db + .select({ id: sites.id }) + .from(sites) + .where(and(eq(sites.id, siteId), eq(sites.organizationId, organizationId), isNull(sites.archivedAt))) + if (!site) throw fail(400, 'Unknown site') + if (areaId) { + const [area] = await db + .select({ id: areas.id }) + .from(areas) + .where(and(eq(areas.id, areaId), eq(areas.siteId, siteId))) + if (!area) throw fail(400, 'Area must belong to the selected site') + } +} + +export interface NewReport { + organizationId: string + title: string + type: IncidentType + severity: Severity + occurredAt: string + siteId: string + areaId?: string | null + locationDetail?: string | null + description?: string | null + immediateAction?: string | null + clientId?: string + /** Signed-in reporter, or null for anonymous and kiosk reports. */ + reporter: SessionUser | null + reporterName?: string | null + anonymous: boolean + kioskId?: string +} + +/** + * Files a report with the next incident number. If `clientId` was already used in the organization + * (a retried submission), returns the existing incident instead of creating a duplicate. + */ +export async function fileReport(db: Db, notifier: Notifier, report: NewReport): Promise<{ id: string; number: number; created: boolean }> { + const { organizationId, reporter, anonymous, kioskId, occurredAt, clientId, ...fields } = report + await assertLocation(db, organizationId, fields.siteId, fields.areaId) + const occurred = parseOccurredAt(occurredAt) + + const existing = async () => { + if (!clientId) return undefined + const [row] = await db + .select({ id: incidents.id, number: incidents.number }) + .from(incidents) + .where(and(eq(incidents.organizationId, organizationId), eq(incidents.clientId, clientId))) + return row && { ...row, created: false } + } + const previous = await existing() + if (previous) return previous + + try { + const created = await db.transaction(async (tx) => { + // Atomic increment: concurrent reports always get distinct, gap-free numbers. + const [{ lastNumber }] = await tx + .insert(incidentCounters) + .values({ organizationId, lastNumber: 1 }) + .onConflictDoUpdate({ target: incidentCounters.organizationId, set: { lastNumber: sql`${incidentCounters.lastNumber} + 1` } }) + .returning({ lastNumber: incidentCounters.lastNumber }) + const [incident] = await tx + .insert(incidents) + .values({ + ...fields, + occurredAt: occurred, + organizationId, + number: lastNumber, + clientId, + anonymous, + reporterId: anonymous ? null : (reporter?.id ?? null), + reporterName: anonymous ? null : (fields.reporterName ?? null), + channel: kioskId ? 'kiosk' : 'web', + kioskId, + }) + .returning({ id: incidents.id, number: incidents.number }) + await auditIncident(tx, anonymous ? null : reporter, organizationId, incident.id, 'create', { + number: lastNumber, + title: fields.title, + type: fields.type, + severity: fields.severity, + ...(kioskId ? { kioskId } : {}), + }) + return incident + }) + notifier.incidentReported(created.id) + return { ...created, created: true } + } catch (error) { + // Two copies of the same submission raced; the other one won. + if (clientId && isUniqueViolation(error)) { + const winner = await existing() + if (winner) return winner + } + throw error + } +} diff --git a/server/routes/incidents.ts b/server/routes/incidents.ts index a231759..0e884b8 100644 --- a/server/routes/incidents.ts +++ b/server/routes/incidents.ts @@ -1,4 +1,4 @@ -import { and, asc, count, desc, eq, ilike, isNull, or, sql, type SQL } from 'drizzle-orm' +import { and, asc, count, desc, eq, ilike, or, type SQL } from 'drizzle-orm' import { Hono } from 'hono' import { bodyLimit } from 'hono/body-limit' import { z } from 'zod' @@ -19,42 +19,19 @@ import { transitionBlocker, transitions } from '../../shared/workflow.ts' import { requireAuth, requireRole } from '../auth/middleware.ts' import type { SessionUser } from '../auth/sessions.ts' import type { Db } from '../db/client.ts' -import { areas, attachments, auditLog, comments, correctiveActions, incidentCounters, incidents, investigations, rootCauses, sites, users } from '../db/schema.ts' +import { auditLog, comments, correctiveActions, incidents, investigations, rootCauses, users } from '../db/schema.ts' import { diff } from '../lib/audit.ts' import { toCsv } from '../lib/csv.ts' +import { saveAttachment } from '../lib/attachments.ts' import { iso } from '../lib/dates.ts' -import { detectFileType } from '../lib/file-type.ts' import { currentUser, fail, validate, type AppEnv } from '../lib/http.ts' import { assertActiveUser, auditIncident, findIncident, loadDetail, selectIncidents, toAttachment, toIncident, visibleTo } from '../lib/incidents.ts' +import { assertLocation, fileReport, parseOccurredAt } from '../lib/reporting.ts' const numberParam = z.object({ number: z.coerce.number().int().positive() }) -/** Reports may be dated slightly ahead to absorb clock differences between devices. */ -const MAX_CLOCK_SKEW_MS = 5 * 60 * 1000 -const MAX_ATTACHMENTS_PER_INCIDENT = 20 const EXPORT_LIMIT = 10_000 -async function assertLocation(db: Db, organizationId: string, siteId: string, areaId: string | null | undefined) { - const [site] = await db - .select({ id: sites.id }) - .from(sites) - .where(and(eq(sites.id, siteId), eq(sites.organizationId, organizationId), isNull(sites.archivedAt))) - if (!site) throw fail(400, 'Unknown site') - if (areaId) { - const [area] = await db - .select({ id: areas.id }) - .from(areas) - .where(and(eq(areas.id, areaId), eq(areas.siteId, siteId))) - if (!area) throw fail(400, 'Area must belong to the selected site') - } -} - -function parseOccurredAt(value: string): Date { - const date = new Date(value) - if (date.getTime() > Date.now() + MAX_CLOCK_SKEW_MS) throw fail(400, 'Occurrence time cannot be in the future') - return date -} - const escapeLike = (value: string) => value.replace(/[\\%_]/g, '\\$&') function listFilter(db: Db, user: SessionUser, { q, type, severity, status, siteId }: Omit) { @@ -122,7 +99,7 @@ export const incidentRoutes = new Hono() i.site.name, i.area?.name, i.locationDetail, - i.anonymous ? 'Anonymous' : i.reporter?.name, + i.anonymous ? 'Anonymous' : (i.reporter?.name ?? i.reporterName ?? (i.kiosk ? `Reporting link: ${i.kiosk.name}` : null)), i.description, i.immediateAction, ]), @@ -133,34 +110,11 @@ export const incidentRoutes = new Hono() .post('/', requireAuth, validate('json', createIncidentSchema), async (c) => { const me = currentUser(c) - const { anonymous, occurredAt, ...input } = c.req.valid('json') + const input = c.req.valid('json') const db = c.get('db') - await assertLocation(db, me.organizationId, input.siteId, input.areaId) - const occurred = parseOccurredAt(occurredAt) - - const created = await db.transaction(async (tx) => { - // Atomic increment: concurrent reports always get distinct, gap-free numbers. - const [{ lastNumber }] = await tx - .insert(incidentCounters) - .values({ organizationId: me.organizationId, lastNumber: 1 }) - .onConflictDoUpdate({ target: incidentCounters.organizationId, set: { lastNumber: sql`${incidentCounters.lastNumber} + 1` } }) - .returning({ lastNumber: incidentCounters.lastNumber }) - const [incident] = await tx - .insert(incidents) - .values({ ...input, occurredAt: occurred, organizationId: me.organizationId, number: lastNumber, anonymous, reporterId: anonymous ? null : me.id }) - .returning({ id: incidents.id, number: incidents.number }) - await auditIncident(tx, anonymous ? null : me, me.organizationId, incident.id, 'create', { - number: lastNumber, - title: input.title, - type: input.type, - severity: input.severity, - }) - return incident - }) - - c.get('notifier').incidentReported(created.id) - const [row] = await selectIncidents(db).where(eq(incidents.id, created.id)) - return c.json({ incident: toIncident(row) }, 201) + const { id, created } = await fileReport(db, c.get('notifier'), { ...input, organizationId: me.organizationId, reporter: me }) + const [row] = await selectIncidents(db).where(eq(incidents.id, id)) + return c.json({ incident: toIncident(row) }, created ? 201 : 200) }) .get('/:number', requireAuth, validate('param', numberParam), async (c) => { @@ -330,29 +284,8 @@ export const incidentRoutes = new Hono() const { incident } = await findIncident(db, me, c.req.valid('param').number) const body = await c.req.parseBody() - const file = body.file - if (!(file instanceof File)) throw fail(400, 'Attach a file in the "file" field') - if (file.size > config.maxUploadBytes) throw fail(413, `Files can be at most ${Math.round(config.maxUploadBytes / 1024 / 1024)} MB`) - const [{ existing }] = await db.select({ existing: count() }).from(attachments).where(eq(attachments.incidentId, incident.id)) - if (existing >= MAX_ATTACHMENTS_PER_INCIDENT) throw fail(409, `An incident can have at most ${MAX_ATTACHMENTS_PER_INCIDENT} attachments`) - - const data = new Uint8Array(await file.arrayBuffer()) - const type = detectFileType(data) - if (!type) throw fail(400, 'Only photos (JPEG, PNG, WebP, GIF, HEIC) and PDFs can be attached') - - const storage = c.get('storage') - const storageKey = await storage.save(data, type.extension) - const fileName = (file.name || `attachment.${type.extension}`).replace(/[\r\n"\\/]/g, '_').slice(0, 200) - try { - const [row] = await db - .insert(attachments) - .values({ incidentId: incident.id, fileName, contentType: type.contentType, sizeBytes: data.byteLength, storageKey, uploadedById: me.id }) - .returning() - await auditIncident(db, me, me.organizationId, incident.id, 'attachment.add', { attachmentId: row.id, fileName }) - return c.json({ attachment: toAttachment(row, me.name) }, 201) - } catch (error) { - await storage.remove(storageKey) - throw error - } + const row = await saveAttachment({ db, storage: c.get('storage'), config }, incident.id, body.file, me.id) + await auditIncident(db, me, me.organizationId, incident.id, 'attachment.add', { attachmentId: row.id, fileName: row.fileName }) + return c.json({ attachment: toAttachment(row, me.name) }, 201) }, ) diff --git a/server/routes/kiosks.test.ts b/server/routes/kiosks.test.ts new file mode 100644 index 0000000..aae9d70 --- /dev/null +++ b/server/routes/kiosks.test.ts @@ -0,0 +1,124 @@ +// oxlint-disable typescript/no-explicit-any -- tests read arbitrary JSON +import { afterAll, beforeAll, describe, expect, it } from 'vitest' +import { createTestContext, hoursAgo } from '../test/helpers.ts' + +let ctx: Awaited> +let north: { id: string } +let south: { id: string } + +const json = (res: Response): Promise => res.json() + +const PNG = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0, 0, 0, 13, 0x49, 0x48, 0x44, 0x52]) + +/** Submits like the kiosk page: multipart with the token header. */ +function kioskReport(token: string, report: Record, files: File[] = []) { + const form = new FormData() + form.append('report', JSON.stringify(report)) + for (const file of files) form.append('files', file) + return ctx.app.request('/api/kiosk/reports', { method: 'POST', headers: { 'x-kiosk-token': token, origin: 'http://safety.test' }, body: form }) +} +const report = (overrides: Record = {}) => ({ title: 'Leaking valve', type: 'hazard', severity: 'medium', occurredAt: hoursAgo(1), siteId: north.id, ...overrides }) + +beforeAll(async () => { + ctx = await createTestContext() + north = await ctx.createSite('North') + south = await ctx.createSite('South') +}) +afterAll(() => ctx.close()) + +describe('reporting links', () => { + it('are managed by safety managers', async () => { + const supervisor = await ctx.createUser('supervisor') + expect((await supervisor.post('/api/kiosks', { name: 'Canteen tablet' })).status).toBe(403) + const res = await ctx.admin.post('/api/kiosks', { name: 'Canteen tablet' }) + expect(res.status).toBe(201) + expect(res.body.kiosk.token).toMatch(/^[\w-]{32}$/) + expect((await ctx.admin.get('/api/kiosks')).body.kiosks.map((k: { name: string }) => k.name)).toContain('Canteen tablet') + }) + + it('let anyone with the token file a report, with photos, and nothing more', async () => { + const { kiosk } = (await ctx.admin.post('/api/kiosks', { name: 'Gate 2' })).body + + const config = await ctx.app.request('/api/kiosk/config', { headers: { 'x-kiosk-token': kiosk.token } }) + expect(await json(config)).toMatchObject({ organization: { name: 'Northstar Co.' }, kiosk: { name: 'Gate 2' } }) + + const res = await kioskReport(kiosk.token, report({ reporterName: 'Luis' }), [new File([PNG], 'valve.png', { type: 'image/png' })]) + expect(res.status).toBe(201) + const { reference, failedFiles } = await json(res) + expect(reference).toMatch(/^INC-\d{4}$/) + expect(failedFiles).toEqual([]) + + const number = Number(reference.slice(4)) + const incident = (await ctx.admin.get(`/api/incidents/${number}`)).body.incident + expect(incident).toMatchObject({ channel: 'kiosk', kiosk: { name: 'Gate 2' }, reporterName: 'Luis', reporter: null, anonymous: false }) + expect(incident.attachments).toHaveLength(1) + + // The token is not a session + expect((await ctx.app.request('/api/incidents', { headers: { 'x-kiosk-token': kiosk.token } })).status).toBe(401) + }) + + it('treat reports without a name as anonymous', async () => { + const { kiosk } = (await ctx.admin.post('/api/kiosks', { name: 'Anon' })).body + const { reference } = await json(await kioskReport(kiosk.token, report())) + const incident = (await ctx.admin.get(`/api/incidents/${Number(reference.slice(4))}`)).body.incident + expect(incident).toMatchObject({ anonymous: true, reporterName: null }) + }) + + it('stop working when revoked', async () => { + const { kiosk } = (await ctx.admin.post('/api/kiosks', { name: 'Old tablet' })).body + await ctx.admin.patch(`/api/kiosks/${kiosk.id}`, { revoked: true }) + expect((await kioskReport(kiosk.token, report())).status).toBe(401) + expect((await kioskReport('made-up-token', report())).status).toBe(401) + }) + + it('can be limited to one site', async () => { + const { kiosk } = (await ctx.admin.post('/api/kiosks', { name: 'North only', siteId: north.id })).body + const config = await json(await ctx.app.request('/api/kiosk/config', { headers: { 'x-kiosk-token': kiosk.token } })) + expect(config.sites.map((s: { id: string }) => s.id)).toEqual([north.id]) + expect((await kioskReport(kiosk.token, report({ siteId: south.id }))).status).toBe(400) + }) + + it('validate reports', async () => { + const { kiosk } = (await ctx.admin.post('/api/kiosks', { name: 'Validation' })).body + const res = await kioskReport(kiosk.token, report({ type: 'explosion' })) + expect(res.status).toBe(400) + expect((await json(res)).issues[0].path).toBe('type') + }) + + it('are rate limited', async () => { + const { kiosk } = (await ctx.admin.post('/api/kiosks', { name: 'Busy' })).body + for (let i = 0; i < 30; i++) expect((await kioskReport(kiosk.token, report({ severity: 'low' }))).status).toBe(201) + expect((await kioskReport(kiosk.token, report({ severity: 'low' }))).status).toBe(429) + }) +}) + +describe('resubmitting the same report (offline retries)', () => { + it('returns the original instead of creating a duplicate', async () => { + const reporter = await ctx.createUser('reporter') + const clientId = crypto.randomUUID() + const first = await reporter.post('/api/incidents', { ...report(), clientId }) + const again = await reporter.post('/api/incidents', { ...report(), clientId }) + expect(first.status).toBe(201) + expect(again.status).toBe(200) + expect(again.body.incident.number).toBe(first.body.incident.number) + }) + + it('holds under simultaneous retries', async () => { + const reporter = await ctx.createUser('reporter', 'racer@example.com') + const clientId = crypto.randomUUID() + const results = await Promise.all([1, 2, 3].map(() => reporter.post('/api/incidents', { ...report(), clientId }))) + expect(new Set(results.map((r) => r.body.incident.number)).size).toBe(1) + }) + + it('does not attach photos twice from a kiosk retry', async () => { + const { kiosk } = (await ctx.admin.post('/api/kiosks', { name: 'Retry' })).body + const clientId = crypto.randomUUID() + const file = () => new File([PNG], 'p.png', { type: 'image/png' }) + const a = await json(await kioskReport(kiosk.token, report({ clientId }), [file()])) + const b = await kioskReport(kiosk.token, report({ clientId }), [file()]) + expect(b.status).toBe(200) + expect((await json(b)).reference).toBe(a.reference) + const incident = (await ctx.admin.get(`/api/incidents/${Number(a.reference.slice(4))}`)).body.incident + expect(incident.attachments).toHaveLength(1) + }) +}) diff --git a/server/routes/kiosks.ts b/server/routes/kiosks.ts new file mode 100644 index 0000000..17c5718 --- /dev/null +++ b/server/routes/kiosks.ts @@ -0,0 +1,177 @@ +import { and, asc, eq, inArray, isNull } from 'drizzle-orm' +import { Hono, type Context } from 'hono' +import { bodyLimit } from 'hono/body-limit' +import { randomBytes } from 'node:crypto' +import { z } from 'zod' +import type { Kiosk, KioskConfig } from '../../shared/api-types.ts' +import { incidentReference } from '../../shared/format.ts' +import { createKioskSchema, kioskReportSchema, updateKioskSchema } from '../../shared/schemas.ts' +import { requireRole } from '../auth/middleware.ts' +import { RateLimiter } from '../auth/rate-limit.ts' +import type { Db } from '../db/client.ts' +import { areas, kiosks, organizations, sites } from '../db/schema.ts' +import { saveAttachment } from '../lib/attachments.ts' +import { audit, diff } from '../lib/audit.ts' +import { iso } from '../lib/dates.ts' +import { currentUser, fail, validate, type AppEnv } from '../lib/http.ts' +import { auditIncident } from '../lib/incidents.ts' +import { fileReport } from '../lib/reporting.ts' + +export const KIOSK_HEADER = 'x-kiosk-token' +const MAX_FILES_PER_REPORT = 5 +const idParam = z.object({ id: z.uuid() }) + +async function toKiosk(db: Db, row: typeof kiosks.$inferSelect): Promise { + const [site] = row.siteId ? await db.select({ id: sites.id, name: sites.name }).from(sites).where(eq(sites.id, row.siteId)) : [] + return { id: row.id, name: row.name, token: row.token, site: site ?? null, lastUsedAt: iso(row.lastUsedAt), revokedAt: iso(row.revokedAt), createdAt: iso(row.createdAt) } +} + +async function assertSite(db: Db, organizationId: string, siteId: string | null | undefined) { + if (!siteId) return + const [site] = await db.select({ id: sites.id }).from(sites).where(and(eq(sites.id, siteId), eq(sites.organizationId, organizationId))) + if (!site) throw fail(400, 'Unknown site') +} + +/** Managing reporting links (signed-in safety managers). */ +export const kioskAdminRoutes = new Hono() + .get('/', requireRole('safety_manager'), async (c) => { + const me = currentUser(c) + const db = c.get('db') + const rows = await db.select().from(kiosks).where(eq(kiosks.organizationId, me.organizationId)).orderBy(asc(kiosks.name)) + return c.json({ kiosks: await Promise.all(rows.map((row) => toKiosk(db, row))) }) + }) + + .post('/', requireRole('safety_manager'), validate('json', createKioskSchema), async (c) => { + const me = currentUser(c) + const db = c.get('db') + const input = c.req.valid('json') + await assertSite(db, me.organizationId, input.siteId) + const [row] = await db + .insert(kiosks) + .values({ ...input, organizationId: me.organizationId, token: randomBytes(24).toString('base64url'), createdById: me.id }) + .returning() + await audit(db, { organizationId: me.organizationId, actorId: me.id, entityType: 'kiosk', entityId: row.id, action: 'create', changes: { name: row.name } }) + return c.json({ kiosk: await toKiosk(db, row) }, 201) + }) + + .patch('/:id', requireRole('safety_manager'), validate('param', idParam), validate('json', updateKioskSchema), async (c) => { + const me = currentUser(c) + const db = c.get('db') + const [current] = await db + .select() + .from(kiosks) + .where(and(eq(kiosks.id, c.req.valid('param').id), eq(kiosks.organizationId, me.organizationId))) + if (!current) throw fail(404, 'Reporting link not found') + const { revoked, ...fields } = c.req.valid('json') + await assertSite(db, me.organizationId, fields.siteId) + const update = { ...fields, revokedAt: revoked === undefined ? undefined : revoked ? (current.revokedAt ?? new Date()) : null } + const changes = diff(current, update) + if (Object.keys(changes).length === 0) return c.json({ kiosk: await toKiosk(db, current) }) + const [row] = await db.update(kiosks).set(update).where(eq(kiosks.id, current.id)).returning() + await audit(db, { organizationId: me.organizationId, actorId: me.id, entityType: 'kiosk', entityId: row.id, action: 'update', changes }) + return c.json({ kiosk: await toKiosk(db, row) }) + }) + +/** + * Endpoints used with a reporting link's token instead of a session. The token travels in a custom + * header, which browsers never send cross-site without a CORS preflight, so these can't be forged + * from another site. + */ +export function kioskPublicRoutes() { + // Each link can file 30 reports per 10 minutes: plenty for a busy shop floor, a brake on abuse. + const limiter = new RateLimiter(30, 10 * 60 * 1000) + + async function kioskFrom(c: Context) { + const token = c.req.header(KIOSK_HEADER) + if (!token) throw fail(401, 'Missing reporting link token') + const [row] = await c + .get('db') + .select() + .from(kiosks) + .where(and(eq(kiosks.token, token), isNull(kiosks.revokedAt))) + if (!row) throw fail(401, 'This reporting link is no longer active. Ask your safety team for a new one.') + return row + } + + return new Hono() + .get('/config', async (c) => { + const kiosk = await kioskFrom(c) + const db = c.get('db') + const [organization] = await db.select({ name: organizations.name }).from(organizations).where(eq(organizations.id, kiosk.organizationId)) + const siteRows = await db + .select() + .from(sites) + .where(and(eq(sites.organizationId, kiosk.organizationId), isNull(sites.archivedAt), kiosk.siteId ? eq(sites.id, kiosk.siteId) : undefined)) + .orderBy(asc(sites.name)) + const areaRows = siteRows.length + ? await db + .select() + .from(areas) + .where(and(inArray(areas.siteId, siteRows.map((s) => s.id)), isNull(areas.archivedAt))) + .orderBy(asc(areas.name)) + : [] + const config: KioskConfig = { + organization, + kiosk: { name: kiosk.name }, + sites: siteRows.map((site) => ({ + id: site.id, + name: site.name, + address: null, + timezone: site.timezone, + archivedAt: null, + areas: areaRows + .filter((area) => area.siteId === site.id) + .map((area) => ({ id: area.id, siteId: area.siteId, parentId: area.parentId, name: area.name, kind: area.kind, archivedAt: null })), + })), + } + return c.json(config) + }) + + // Multipart: a `report` field holding the JSON report, plus up to 5 `files`. + .post('/reports', async (c, next) => bodyLimit({ maxSize: c.get('config').maxUploadBytes * MAX_FILES_PER_REPORT + 256 * 1024, onError: (c) => c.json({ error: 'Files are too large' }, 413) })(c, next), async (c) => { + const kiosk = await kioskFrom(c) + if (!limiter.attempt(kiosk.id)) throw fail(429, 'Too many reports from this link right now. Please try again in a few minutes.') + const db = c.get('db') + + const body = await c.req.parseBody({ all: true }) + let json: unknown + try { + json = JSON.parse(String(body.report ?? '')) + } catch { + throw fail(400, 'Missing report') + } + const parsed = kioskReportSchema.safeParse(json) + if (!parsed.success) { + return c.json({ error: 'Invalid request', issues: parsed.error.issues.map((issue) => ({ path: issue.path.join('.'), message: issue.message })) }, 400) + } + if (kiosk.siteId && parsed.data.siteId !== kiosk.siteId) throw fail(400, 'This reporting link is for a different site') + const files = ([] as unknown[]).concat(body.files ?? []).filter((file) => file instanceof File) + if (files.length > MAX_FILES_PER_REPORT) throw fail(400, `Attach at most ${MAX_FILES_PER_REPORT} photos`) + + const { reporterName, ...report } = parsed.data + const { id, number, created } = await fileReport(db, c.get('notifier'), { + ...report, + organizationId: kiosk.organizationId, + reporter: null, + reporterName, + anonymous: !reporterName, + kioskId: kiosk.id, + }) + await db.update(kiosks).set({ lastUsedAt: new Date() }).where(eq(kiosks.id, kiosk.id)) + + // Files are only taken with the first copy of a submission, so retries don't duplicate photos. + const failed: string[] = [] + if (created) { + for (const file of files) { + try { + const row = await saveAttachment({ db, storage: c.get('storage'), config: c.get('config') }, id, file, null) + await auditIncident(db, null, kiosk.organizationId, id, 'attachment.add', { attachmentId: row.id, fileName: row.fileName }) + } catch (error) { + failed.push(`${(file as File).name}: ${error instanceof Error ? error.message : 'upload failed'}`) + } + } + } + // Only the reference goes back: people using a link can't read reports. + return c.json({ reference: incidentReference(number), failedFiles: failed }, created ? 201 : 200) + }) +} diff --git a/shared/api-types.ts b/shared/api-types.ts index d657de7..ee97fbb 100644 --- a/shared/api-types.ts +++ b/shared/api-types.ts @@ -73,6 +73,28 @@ export interface Incident { immediateAction: string | null anonymous: boolean reporter: UserRef | null + /** Name given by someone reporting without an account. */ + reporterName: string | null + /** How the report arrived; `kiosk` covers kiosk tablets and QR codes on reporting links. */ + channel: 'web' | 'kiosk' + kiosk: { id: string; name: string } | null +} + +export interface Kiosk { + id: string + name: string + token: string + site: { id: string; name: string } | null + lastUsedAt: string | null + revokedAt: string | null + createdAt: string +} + +/** What a reporting link may see: just enough to fill in the report form. */ +export interface KioskConfig { + organization: { name: string } + kiosk: { name: string } + sites: Site[] } export interface Investigation { diff --git a/shared/schemas.ts b/shared/schemas.ts index 9511ac1..33da142 100644 --- a/shared/schemas.ts +++ b/shared/schemas.ts @@ -39,10 +39,12 @@ export const createIncidentSchema = z.object({ description: optionalText(10_000), immediateAction: optionalText(10_000), anonymous: z.boolean().default(false), + /** Random id from the reporting device; resubmitting the same id returns the existing report. */ + clientId: z.uuid().optional(), }) /** Status changes go through transitions, not updates. */ -export const updateIncidentSchema = createIncidentSchema.omit({ anonymous: true }).partial() +export const updateIncidentSchema = createIncidentSchema.omit({ anonymous: true, clientId: true }).partial() export const transitionSchema = z.object({ to: z.enum(incidentStatuses), note: optionalText(5_000) }) @@ -87,6 +89,13 @@ export const actionListQuery = z.object({ filter: z.enum(['open', 'overdue', 'done', 'all']).default('open'), }) +export const createKioskSchema = z.object({ name, siteId: z.uuid().nullish() }) + +export const updateKioskSchema = z.object({ name: name.optional(), siteId: z.uuid().nullish(), revoked: z.boolean().optional() }) + +/** Report filed through a reporting link (kiosk tablet or QR code), without an account. */ +export const kioskReportSchema = createIncidentSchema.omit({ anonymous: true }).extend({ reporterName: optionalText(200) }) + export const emailOnlySchema = z.object({ email }) export const tokenSchema = z.object({ token: z.string().min(20).max(200) }) @@ -105,6 +114,7 @@ export const incidentListQuery = z.object({ export type SetupInput = z.infer export type CreateIncidentInput = z.input +export type KioskReportInput = z.input export type UpdateIncidentInput = z.infer export type CreateActionInput = z.input export type UpdateActionInput = z.input diff --git a/src/App.tsx b/src/App.tsx index 4c2730f..8f2b2e3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,9 +5,11 @@ import { Actions } from './pages/Actions' import { Analytics } from './pages/Analytics' import { Login, MagicLinkLanding, ResetPassword, Setup } from './pages/Auth' import { IncidentDetail } from './pages/IncidentDetail' +import { Kiosk } from './pages/Kiosk' import { Incidents } from './pages/Incidents' import { Locations } from './pages/Locations' import { Overview } from './pages/Overview' +import { QrSheet } from './pages/QrSheet' import { ReportIncident } from './pages/ReportIncident' import { Settings } from './pages/Settings' @@ -18,12 +20,14 @@ export default function App() { } /> } /> } /> + } /> }> } /> } /> } /> } /> } /> + } /> } /> } /> } /> diff --git a/src/components/AppLayout.tsx b/src/components/AppLayout.tsx index 8cce311..a137690 100644 --- a/src/components/AppLayout.tsx +++ b/src/components/AppLayout.tsx @@ -1,7 +1,10 @@ import { useState } from 'react' import { Navigate, Outlet, useLocation } from 'react-router-dom' import { useActions, useMe, useSetupStatus } from '../lib/queries' +import type { QueuedItem } from '../lib/outbox' +import { useOutboxSync } from '../lib/use-outbox' import { Header } from './Header' +import { OutboxBanner } from './OutboxBanner' import { ErrorMessage, Loading } from './QueryState' import { Sidebar } from './Sidebar' @@ -12,6 +15,9 @@ export function AppLayout() { const location = useLocation() const [menuOpen, setMenuOpen] = useState(false) const myOpenActions = useActions('mine', 'open', !!me.data) + const userId = me.data?.user.id + const belongs = userId ? (item: QueuedItem) => item.kind === 'report' && item.userId === userId : null + useOutboxSync(belongs) if (me.isPending) return if (me.isError) return @@ -28,6 +34,7 @@ export function AppLayout() { setMenuOpen(false)} badges={{ '/actions': open.length }} />
setMenuOpen(true)} overdueActions={overdue} /> +
diff --git a/src/components/AuthLayout.tsx b/src/components/AuthLayout.tsx index bd5b65e..dff2c13 100644 --- a/src/components/AuthLayout.tsx +++ b/src/components/AuthLayout.tsx @@ -1,5 +1,6 @@ import { ShieldCheck } from 'lucide-react' import type { ReactNode } from 'react' +import { LanguageToggle } from './LanguageToggle' import { panel } from './styles' /** Centered card for sign-in, setup and email-link pages. */ @@ -18,6 +19,9 @@ export function AuthLayout({ title, copy, children }: { title: string; copy?: st {copy &&

{copy}

}
{children}
+
+ +
) diff --git a/src/components/Badges.tsx b/src/components/Badges.tsx index 8b8c214..ef98319 100644 --- a/src/components/Badges.tsx +++ b/src/components/Badges.tsx @@ -17,4 +17,4 @@ export function SeverityLabel({ severity }: { severity: Severity }) { ) } -export const OverdueBadge = () => Overdue +export const OverdueBadge = ({ label = 'Overdue' }: { label?: string }) => {label} diff --git a/src/components/FormSection.tsx b/src/components/FormSection.tsx index 745c898..753cdd2 100644 --- a/src/components/FormSection.tsx +++ b/src/components/FormSection.tsx @@ -22,11 +22,19 @@ export function FormSection({ number, title, copy, children }: FormSectionProps) ) } -export function Field({ label, optional = false, children }: { label: string; optional?: boolean; children: ReactNode }) { +interface FieldProps { + label: string + optional?: boolean + /** Translated "Optional" marker. */ + optionalLabel?: string + children: ReactNode +} + +export function Field({ label, optional = false, optionalLabel = 'Optional', children }: FieldProps) { return ( ) diff --git a/src/components/Header.tsx b/src/components/Header.tsx index fc50c81..49e409c 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,6 +1,7 @@ import { Bell, Menu, Search } from 'lucide-react' import { useState, type FormEvent } from 'react' import { Link, useLocation, useNavigate } from 'react-router-dom' +import { useI18n } from '../i18n' import { initials } from '../lib/initials' import { pageTitle } from '../lib/navigation' import type { Me } from '../lib/queries' @@ -10,6 +11,7 @@ export function Header({ me, onOpenMenu, overdueActions }: { me: Me; onOpenMenu: const { pathname } = useLocation() const navigate = useNavigate() const [query, setQuery] = useState('') + const { t } = useI18n() const search = (event: FormEvent) => { event.preventDefault() @@ -19,7 +21,7 @@ export function Header({ me, onOpenMenu, overdueActions }: { me: Me; onOpenMenu: return (
-
@@ -33,14 +35,14 @@ export function Header({ me, onOpenMenu, overdueActions }: { me: Me; onOpenMenu: setQuery(event.target.value)} /> - + diff --git a/src/components/IncidentTable.tsx b/src/components/IncidentTable.tsx index 903c53c..be47969 100644 --- a/src/components/IncidentTable.tsx +++ b/src/components/IncidentTable.tsx @@ -45,7 +45,7 @@ export function IncidentTable({ incidents, wide = false }: { incidents: Incident {incident.title} - {incident.reference} · {incident.anonymous ? 'Anonymous' : (incident.reporter?.name ?? 'Unknown')} + {incident.reference} · {incident.anonymous ? 'Anonymous' : (incident.reporter?.name ?? incident.reporterName ?? 'Unknown')}
diff --git a/src/components/LanguageToggle.tsx b/src/components/LanguageToggle.tsx new file mode 100644 index 0000000..e036e86 --- /dev/null +++ b/src/components/LanguageToggle.tsx @@ -0,0 +1,12 @@ +import { Languages } from 'lucide-react' +import { useI18n } from '../i18n' + +/** Switches between English and Spanish; shows the language you'd switch to, in that language. */ +export function LanguageToggle({ className = '' }: { className?: string }) { + const { lang, setLang, t } = useI18n() + return ( + + ) +} diff --git a/src/components/OutboxBanner.tsx b/src/components/OutboxBanner.tsx new file mode 100644 index 0000000..bf1a728 --- /dev/null +++ b/src/components/OutboxBanner.tsx @@ -0,0 +1,45 @@ +import { CloudOff, RefreshCw, Trash2 } from 'lucide-react' +import { useI18n } from '../i18n' +import { outbox, type QueuedItem } from '../lib/outbox' +import { useOnline, useOutbox } from '../lib/use-outbox' + +/** Offline notice plus any reports still waiting on this device. */ +export function OutboxBanner({ belongs }: { belongs: (item: QueuedItem) => boolean }) { + const { t } = useI18n() + const online = useOnline() + const { items, syncing } = useOutbox() + const mine = items.filter(belongs) + if (online && mine.length === 0) return null + + return ( +
+ {!online && ( +

+ {t.outbox.offline} +

+ )} + {mine.length > 0 && ( +
+
+ {t.outbox.waiting(mine.length)} + {online && ( + + )} +
+ {mine + .filter((item) => item.rejected) + .map((item) => ( +

+ “{item.report.title}”: {t.outbox.failed(item.lastError ?? '')} + +

+ ))} +
+ )} +
+ ) +} diff --git a/src/components/QrCode.tsx b/src/components/QrCode.tsx new file mode 100644 index 0000000..ce42448 --- /dev/null +++ b/src/components/QrCode.tsx @@ -0,0 +1,19 @@ +import QRCode from 'qrcode' +import { useMemo } from 'react' + +/** QR code as crisp SVG squares (prints sharply at any size). */ +export function QrCode({ value, size = 160, label }: { value: string; size?: number; label: string }) { + const { path, count } = useMemo(() => { + const { modules } = QRCode.create(value, { errorCorrectionLevel: 'M' }) + let d = '' + for (let y = 0; y < modules.size; y++) for (let x = 0; x < modules.size; x++) if (modules.get(x, y)) d += `M${x} ${y}h1v1h-1z` + return { path: d, count: modules.size } + }, [value]) + const margin = 2 + return ( + + + + + ) +} diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 1bb63e0..1dd87e4 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -1,10 +1,13 @@ import { Info, LogOut, Plus, Settings, ShieldCheck, X } from 'lucide-react' import { NavLink, useNavigate } from 'react-router-dom' +import { useI18n } from '../i18n' +import { outbox } from '../lib/outbox' import { initials } from '../lib/initials' import { roleLabel } from '../lib/labels' import { primaryNav } from '../lib/navigation' import { useLogout, type Me } from '../lib/queries' import { Eyebrow } from './Eyebrow' +import { LanguageToggle } from './LanguageToggle' import { iconButton } from './styles' const navLink = ({ isActive }: { isActive: boolean }) => @@ -21,6 +24,13 @@ interface SidebarProps { export function Sidebar({ me, open, onClose, badges }: SidebarProps) { const logout = useLogout() const navigate = useNavigate() + const { t } = useI18n() + + const signOut = () => { + const unsent = outbox.getState().items.filter((item) => item.kind === 'report' && item.userId === me.user.id).length + if (unsent && !confirm(t.outbox.signOutWarning(unsent))) return + logout.mutate(undefined, { onSuccess: () => navigate('/login') }) + } return (