diff --git a/.agents/docs/architecture/auth-and-permissions.md b/.agents/docs/architecture/auth-and-permissions.md index fc5a017fe..36ac2eca1 100644 --- a/.agents/docs/architecture/auth-and-permissions.md +++ b/.agents/docs/architecture/auth-and-permissions.md @@ -72,14 +72,23 @@ that the controller actually forwards `@CurrentUser('ability')` — `EntityOpera is optional, so a controller that simply never passes it compiles and runs. **A defined ability holding no rule for the queried subject does not produce a deny-all filter — -CASL's `accessibleBy` throws `ForbiddenError`.** That error is not an `HttpException`, so the +`accessibleQuery` throws CASL's `ForbiddenError`.** That error is not an `HttpException`, so the global exception filter renders it as a 500. It is reachable whenever the route guard names a different subject than the service queries: a STANDARD user passes a `read Instrument` guard but holds no rule on `InstrumentRecord`, so a record query made on their behalf throws. The throw is deliberate — `accessibleQuery` is kept as-is rather than returning a deny-all filter — so where such a caller is legitimate, guard the query with `ability.can(action, subject)` and return the empty result instead; `findInstrumentIdsBySubject` in `src/instruments/instruments.service.ts` is -the reference example. +the reference example. `ability.can` refuses in every case where the query would throw, so the +guard always pre-empts it. + +The throw is `accessibleQuery`'s own. `@casl/prisma` 2's `accessibleBy(...).ofType(...)` no longer +throws: it returns `{ OR: [] }`, which Prisma ignores once it is nested in an `AND` +(prisma/prisma#17367, reproducible on this MongoDB stack), so passed on it would lift the +restriction rather than apply it. `accessibleQuery` throws on that marker instead, under exactly the +condition `@casl/prisma` 1 threw. That is also why the client in `src/core/prisma.ts` carries no +`createCaslExtension()`, which upstream offers to turn the marker into an empty result: the marker +never reaches Prisma. Call `accessibleBy` only through `accessibleQuery`. One call site uses `{ ...accessibleQuery(...), id: subjectId }` instead of `AND: [...]` (`src/subjects/subjects.service.ts`). Spreading merges keys and will silently lose a condition if @@ -208,8 +217,8 @@ add it to the `$GroupScopableSubjectName` exclusion. - `src/auth/__tests__/ability.factory.test.ts` — role-to-rule mapping. Each case asserts an allow _and_ a deny. -- `src/auth/__tests__/ability.utils.test.ts` — pins the `undefined` ability behavior and - `forcedAppSubject`. +- `src/auth/__tests__/ability.utils.test.ts` — pins the `undefined` ability behavior, the + no-rule throw (including `cannot` rules) and `forcedAppSubject`, against the real CASL. - `src/auth/guards/__tests__/jwt-auth.guard.test.ts` — the guard's own branches. Service tests mock the Prisma layer, so they verify the arguments passed to the model, not the diff --git a/.agents/docs/architecture/testing-strategy.md b/.agents/docs/architecture/testing-strategy.md index 8be9ddc7e..4d8417fbb 100644 --- a/.agents/docs/architecture/testing-strategy.md +++ b/.agents/docs/architecture/testing-strategy.md @@ -31,29 +31,29 @@ path exercised against a real database is Playwright. Twenty-one. Scope a run with `pnpm exec vitest --project `; the name is the `name` field in that package's config, which is **not** always the directory name. -| Project | Package | Notable config | -| ------------------------ | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `api` | `apps/api` | libnest SWC plugin, confined to `apps/api` sources; `globals: true` | -| `web` | `apps/web` | `environment: 'happy-dom'`; redeclares the `@` alias | -| `gateway` | `apps/gateway` | node environment; redeclares the `@` alias. Request schemas, `resolveLanguage`, and the HTML `src/entry-server.tsx` renders — the routers and hydration are covered by `testing/src/specs/gateway-*.spec.ts`. A component test opts into happy-dom per file with a `// @vitest-environment happy-dom` docblock | -| `instrument-bundler` | `packages/instrument-bundler` | | -| `instrument-library` | `packages/instrument-library` | `environment: 'happy-dom'`; `resolve.alias` maps `/runtime/v1/@[/]` to `vendor/@/src/` and `/runtime/v1/@opendatacapture/runtime-core` to `packages/runtime-core/src`, so no `runtime/v1` build is needed. Tests go in top-level `src/__tests__/` only — see `packages/instrument-library/AGENTS.md` | -| `instrument-interpreter` | `packages/instrument-interpreter` | | -| `instrument-stubs` | `packages/instrument-stubs` | node environment; tests are `.test.js` (no tsconfig, so eslint cannot parse a `.ts` file here) | -| `instrument-utils` | `packages/instrument-utils` | | -| `playground` | `apps/playground` | node environment; redeclares the `@` alias. Only `src/preview/protocol.ts` is unit-testable — the preview frame, its origin split and the message bridge are covered by `testing/src/specs/playground.spec.ts` | -| `playground-url` | `packages/playground-url` | | -| `react-core` | `packages/react-core` | `environment: 'happy-dom'` | -| `release-info` | `packages/release-info` | | -| `runtime-bundler` | `packages/runtime-bundler` | | -| `runtime-core` | `packages/runtime-core` | node environment, `// @vitest-environment happy-dom` per file for the browser branches of `i18n.ts`; relative imports carry `.js` (Node16). `*.test-d.ts` are checked by `tsc` in `lint`, not vitest | -| `runtime-internal` | `packages/runtime-internal` | node environment; `bootstrap.js` and `worker.js` are tested against stubbed browser globals — see `packages/runtime-internal/AGENTS.md` | -| `runtime-meta` | `packages/runtime-meta` | | -| `schemas` | `packages/schemas` | | -| `serve-instrument` | `packages/serve-instrument` | node environment; `test/` mocks `fs.watch` (never closed by `Server.stop()`, see `packages/serve-instrument/AGENTS.md`) and stubs the built `client.js`/`__TAILWIND_STYLES__` that only exist post-build | -| `subject-utils` | `packages/subject-utils` | | -| `vite-plugin-runtime` | `packages/vite-plugin-runtime` | | -| `runtime-v1` | `runtime/v1` | directory is `v1`, project is `runtime-v1` | +| Project | Package | Notable config | +| ------------------------ | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `api` | `apps/api` | libnest SWC plugin, confined to `apps/api` sources; `globals: true` | +| `web` | `apps/web` | `environment: 'happy-dom'`; redeclares the `@` alias | +| `gateway` | `apps/gateway` | node environment; redeclares the `@` alias. Request schemas, `resolveLanguage`, and the HTML `src/entry-server.tsx` renders — the routers and hydration are covered by `testing/src/specs/gateway-*.spec.ts`. A component test opts into happy-dom per file with a `// @vitest-environment happy-dom` docblock | +| `instrument-bundler` | `packages/instrument-bundler` | | +| `instrument-library` | `packages/instrument-library` | `environment: 'happy-dom'`; `resolve.alias` maps `/runtime/v1/@[/]` to `vendor/@/src/` and `/runtime/v1/@opendatacapture/runtime-core` to `packages/runtime-core/src`, so no `runtime/v1` build is needed. Tests go in top-level `src/__tests__/` only — see `packages/instrument-library/AGENTS.md` | +| `instrument-interpreter` | `packages/instrument-interpreter` | | +| `instrument-stubs` | `packages/instrument-stubs` | node environment; tests are `.test.js` (no tsconfig, so eslint cannot parse a `.ts` file here) | +| `instrument-utils` | `packages/instrument-utils` | | +| `playground` | `apps/playground` | node environment; redeclares the `@` alias. Pure code under `src/preview/`, plus components rendered to markup with `react-dom/server` (`src/components/Resizable/`) — the preview frame, its origin split, the message bridge and the editor/preview split are covered by `testing/src/specs/playground.spec.ts`. A component test opts into happy-dom per file with a `// @vitest-environment happy-dom` docblock (`src/components/Editor/__tests__/MonacoEditor.test.tsx`, against a mocked `monaco-editor`) | +| `playground-url` | `packages/playground-url` | | +| `react-core` | `packages/react-core` | `environment: 'happy-dom'` | +| `release-info` | `packages/release-info` | | +| `runtime-bundler` | `packages/runtime-bundler` | | +| `runtime-core` | `packages/runtime-core` | node environment, `// @vitest-environment happy-dom` per file for the browser branches of `i18n.ts`; relative imports carry `.js` (Node16). `*.test-d.ts` are checked by `tsc` in `lint`, not vitest | +| `runtime-internal` | `packages/runtime-internal` | node environment; `bootstrap.js` and `worker.js` are tested against stubbed browser globals — see `packages/runtime-internal/AGENTS.md` | +| `runtime-meta` | `packages/runtime-meta` | | +| `schemas` | `packages/schemas` | | +| `serve-instrument` | `packages/serve-instrument` | node environment; `test/` mocks `fs.watch` (never closed by `Server.stop()`, see `packages/serve-instrument/AGENTS.md`) and stubs the built `client.js`/`__TAILWIND_STYLES__` that only exist post-build | +| `subject-utils` | `packages/subject-utils` | | +| `vite-plugin-runtime` | `packages/vite-plugin-runtime` | | +| `runtime-v1` | `runtime/v1` | directory is `v1`, project is `runtime-v1` | Everything else has no unit tests and no way to run them: `apps/outreach` and `packages/{demo, instrument-guidelines, licenses}`. `testing/`, `storybook/` and `vendor/**` fall outside the @@ -63,6 +63,11 @@ project globs by design — `testing/` is Playwright, not vitest. - **There are no setup files anywhere in the repo.** No `setupFiles`, no `globalSetup`. Whatever a test needs, it arranges in its own body. +- **Every mock's recorded calls are cleared before each test** — Vitest's `clearMocks` defaults to + `true`, and no config here overrides it. A call made at import time or in `beforeAll` is gone by + the time an `it` runs, so copy what the assertion reads into a variable at the end of `beforeAll`, + as `packages/serve-instrument/src/__tests__/client.test.tsx` does. Implementations survive the + clear. - **`@testing-library/jest-dom` is not installed.** `toBeInTheDocument()` does not exist; assert `expect(screen.getByText(x)).toBeTruthy()`. - Workspace packages export TypeScript source from `exports` (`@opendatacapture/schemas` maps diff --git a/.agents/docs/playbooks/add-vitest-project.md b/.agents/docs/playbooks/add-vitest-project.md index da582ff6e..a2c7cb5fe 100644 --- a/.agents/docs/playbooks/add-vitest-project.md +++ b/.agents/docs/playbooks/add-vitest-project.md @@ -34,7 +34,7 @@ of your file means the config is absent. ```ts import { defineProject, mergeConfig } from 'vitest/config'; - import baseConfig from '../../vitest.config'; + import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, @@ -52,6 +52,14 @@ of your file means the config is absent. rather than the repo. Every project file uses `defineProject` — `defineConfig` belongs to the root config alone. + Merge the named `baseConfig`, never the root's default export. The default export adds `coverage` + and `projects`, and Vitest reads a `projects` field inside a project config as a nested set of + projects, re-resolved against the package directory, so every run stops before collecting a file: + + ``` + Error: No projects were found in "packages/schemas/vitest.config.ts". Make sure your configuration is correct. + ``` + 3. **Name the project after the directory.** The `name` field is the string `--project` takes, and it is the directory basename everywhere except `runtime/v1`, whose project is `runtime-v1` because `v1` names nothing on its own. Kebab-case, no `@opendatacapture/` scope. @@ -76,19 +84,11 @@ of your file means the config is absent. `packages/runtime-bundler` and `packages/runtime-meta` do — a `test/` directory outside the tsconfig `include` is type-checked by nothing. -6. **Add the `test` script, and do not rely on it.** `"test": "vitest"` under `packages/` and - `runtime/`, `"test": "env-cmd -f ../../.env vitest"` for an app, matching every project that - already exists. Running it does not work today: `mergeConfig` inherits the root `test.projects` - globs along with everything else, and started from inside the package they re-resolve against that - directory and match nothing — - - ``` - Error: No projects were found. Make sure your configuration is correct. The projects definition: […] - ``` - - Scope a run from the repo root instead: `pnpm exec vitest --project `. Root `pnpm test` runs - the projects directly and never reads this script; `vitest` is a root devDependency, so the package - declares nothing. +6. **Add the `test` script.** `"test": "vitest"` under `packages/` and `runtime/`, + `"test": "env-cmd -f ../../.env vitest"` for an app, matching every project that already exists. + `pnpm --filter @opendatacapture/ test` runs this one project from the package directory. Root + `pnpm test` runs the projects directly and never reads this script; `vitest` is a root + devDependency, so the package declares nothing. 7. **Place the test file inside the inherited glob.** That is `**/*.{test,spec}.?(c|m)[jt]s?(x)`, relative to the package `root`; the house convention is a `__tests__/` folder beside the subject, diff --git a/.agents/docs/playbooks/promote-to-react-core.md b/.agents/docs/playbooks/promote-to-react-core.md index 743814565..fdba18fe2 100644 --- a/.agents/docs/playbooks/promote-to-react-core.md +++ b/.agents/docs/playbooks/promote-to-react-core.md @@ -62,7 +62,7 @@ so nothing that passed lint in `apps/web` fails on style here; what breaks is re 6. **Repoint every `@/…` import.** `packages/react-core/tsconfig.json` declares one path mapping, `/runtime/v1/*` — there is no `@/*` here, so every `@/…` specifier is a module-resolution error. - Storybook agrees: its `vite.config.js` resolves `@` through a `customResolver` keyed on the + Storybook agrees: its `vite.config.js` resolves `@` through a `source-root-alias` plugin keyed on the importing file and returns `null` for anything outside `apps/web/src` and `apps/playground/src`. `@/components/*` becomes a relative sibling import. Everything else — `@/store`, `@/hooks/*`, `@/config`, `@/services/*`, `@/utils/*` — does not move; it becomes a prop or callback per step 5. diff --git a/.gitignore b/.gitignore index 9fda10d4a..eb6b72b8d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ node_modules # testing coverage +.vitest # build build diff --git a/apps/api/AGENTS.md b/apps/api/AGENTS.md index ec418bb23..a9921157a 100644 --- a/apps/api/AGENTS.md +++ b/apps/api/AGENTS.md @@ -253,9 +253,9 @@ Provider overrides are deliberately not offered — nothing needs one yet. Addin The `apps/api/vitest.config.ts` `libnest` plugin is required — it applies the SWC decorator transforms, without which `@Injectable`/`@Body` metadata does not exist at runtime. The config -confines SWC to files under `apps/api` and leaves workspace packages to esbuild, as in every other -project. Letting SWC transform them too makes the merged coverage report count each of their -functions twice. +confines SWC to files under `apps/api` and leaves workspace packages to Vite's Oxc transform, as in +every other project; its `oxc.exclude` keeps Oxc off `apps/api` itself. Letting SWC transform them +too makes the merged coverage report count each of their functions twice. Ignore `apps/api/.vscode/test/*` — it is stale, never runs, and references modules that no longer exist. diff --git a/apps/api/package.json b/apps/api/package.json index 16aeb95ca..23f3c09b8 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -17,21 +17,20 @@ "dependencies": { "@aws-sdk/client-s3": "^3.1141.0", "@aws-sdk/s3-request-presigner": "^3.1141.0", - "@casl/ability": "^6.7.5", - "@casl/prisma": "^1.5.1", + "@casl/ability": "catalog:", + "@casl/prisma": "^2.0.2", "@douglasneuroinformatics/libcrypto": "catalog:", "@douglasneuroinformatics/libjs": "catalog:", - "@douglasneuroinformatics/libnest": "^9.0.0", + "@douglasneuroinformatics/libnest": "^10.0.0", "@douglasneuroinformatics/libpasswd": "catalog:", "@douglasneuroinformatics/libstats": "catalog:", - "@faker-js/faker": "~10.2.0", + "@faker-js/faker": "^10.6.0", "@nestjs/axios": "^12.0.1", - "@nestjs/common": "^11.2.6", - "@nestjs/core": "^11.2.6", + "@nestjs/common": "^12.1.1", + "@nestjs/core": "^12.1.1", "@nestjs/jwt": "^12.0.2", "@nestjs/passport": "^12.0.0", - "@nestjs/platform-express": "^11.2.6", - "@nestjs/platform-fastify": "^11.2.6", + "@nestjs/platform-fastify": "^12.1.1", "@nestjs/throttler": "^6.7.1", "@opendatacapture/demo": "workspace:*", "@opendatacapture/instrument-bundler": "workspace:*", @@ -54,13 +53,13 @@ "nodemailer": "catalog:", "passport": "^0.7.0", "passport-jwt": "^4.0.1", - "reflect-metadata": "^0.1.14", + "reflect-metadata": "^0.2.2", "rxjs": "^7.8.2", "ts-pattern": "workspace:ts-pattern__5.x@*", "zod": "workspace:zod__3.x@*" }, "devDependencies": { - "@nestjs/testing": "^11.2.6", + "@nestjs/testing": "^12.1.1", "@types/express": "^5.0.0", "@types/passport": "^1.0.17", "@types/passport-jwt": "^4.0.1", diff --git a/apps/api/src/auth/__tests__/ability.factory.test.ts b/apps/api/src/auth/__tests__/ability.factory.test.ts index 52c025159..04bc7d9c6 100644 --- a/apps/api/src/auth/__tests__/ability.factory.test.ts +++ b/apps/api/src/auth/__tests__/ability.factory.test.ts @@ -89,6 +89,29 @@ describe('AbilityFactory', () => { expect(ability.can('manage', subject('Group', { id: 'group-2' }) as any)).toBe(false); }); + // CASL 7 treats conditions that semantically match everything as no conditions at all, which in a + // `where` means no restriction. These pin that a group condition, even over no groups, is not one. + it.each([ + ['InstrumentRecord', ['group-1', 'group-2'], { groupId: { in: ['group-1', 'group-2'] } }], + ['Session', ['group-1', 'group-2'], { groupId: { in: ['group-1', 'group-2'] } }], + ['Subject', ['group-1', 'group-2'], { groupIds: { hasSome: ['group-1', 'group-2'] } }], + ['User', ['group-1', 'group-2'], { groupIds: { hasSome: ['group-1', 'group-2'] } }], + ['InstrumentRecord', [], { groupId: { in: [] } }], + ['Subject', [], { groupIds: { hasSome: [] } }] + ] as const)("should confine a group manager's %s query to the groups %j", (modelName, groupIds, condition) => { + const ability = abilityFactory.createForPayload({ + additionalPermissions: undefined, + basePermissionLevel: 'GROUP_MANAGER', + firstName: 'Test', + groups: groupIds.map((id) => ({ id })), + id: 'user-1', + lastName: 'User', + username: 'manager-user' + } as any); + + expect(accessibleQuery(ability, 'read', modelName)).toStrictEqual({ OR: [condition] }); + }); + it('should restrict series deletion to the manager group', () => { const ability = abilityFactory.createForPayload({ additionalPermissions: undefined, diff --git a/apps/api/src/auth/__tests__/ability.utils.test.ts b/apps/api/src/auth/__tests__/ability.utils.test.ts index b016e9ba1..1c18ae07c 100644 --- a/apps/api/src/auth/__tests__/ability.utils.test.ts +++ b/apps/api/src/auth/__tests__/ability.utils.test.ts @@ -1,25 +1,58 @@ -import { describe, expect, it, vi } from 'vitest'; +import { ForbiddenError } from '@casl/ability'; +import { describe, expect, it } from 'vitest'; import { accessibleQuery, createAppAbility, forcedAppSubject } from '../ability.utils'; -const accessibleBy = vi.hoisted(() => vi.fn()); - -vi.mock('@casl/prisma/runtime', () => ({ - createAccessibleByFactory: () => accessibleBy -})); - describe('accessibleQuery', () => { it('should return an empty object if ability is undefined', () => { expect(accessibleQuery(undefined, 'manage', 'User')).toStrictEqual({}); - expect(accessibleBy).not.toHaveBeenCalled(); }); - it('should call accessibleBy with the correct parameters and return the result of accessibleBy for the model', () => { - accessibleBy.mockReturnValueOnce({ - User: 'QUERY' + + it('should return an empty object for an unconditional rule, since it restricts nothing', () => { + const ability = createAppAbility([{ action: 'manage', subject: 'all' }]); + expect(accessibleQuery(ability, 'read', 'Subject')).toStrictEqual({}); + }); + + it('should return the conditions of the rules granting the action on the model', () => { + const ability = createAppAbility([ + { action: 'read', conditions: { groupIds: { hasSome: ['group-1'] } }, subject: 'Subject' }, + { action: 'read', conditions: { groupId: { in: ['group-1'] } }, subject: 'Session' } + ]); + expect(accessibleQuery(ability, 'read', 'Subject')).toStrictEqual({ OR: [{ groupIds: { hasSome: ['group-1'] } }] }); + }); + + it('should throw a ForbiddenError when no rule grants the action on the model, rather than filter', () => { + const ability = createAppAbility([{ action: 'read', subject: 'Session' }]); + expect(() => accessibleQuery(ability, 'read', 'Subject')).toThrow(ForbiddenError); + expect(() => accessibleQuery(ability, 'read', 'Subject')).toThrow(`It's not allowed to run "read" on "Subject"`); + }); + + it('should throw when an unconditional cannot rule outranks every can rule', () => { + const ability = createAppAbility([ + { action: 'read', conditions: { groupIds: { hasSome: ['group-1'] } }, subject: 'Subject' }, + { action: 'read', inverted: true, subject: 'Subject' } + ]); + expect(() => accessibleQuery(ability, 'read', 'Subject')).toThrow(ForbiddenError); + }); + + it('should throw when the only rules for the model are conditional cannot rules', () => { + const ability = createAppAbility([ + { action: 'read', conditions: { groupIds: { hasSome: ['group-1'] } }, inverted: true, subject: 'Subject' } + ]); + expect(() => accessibleQuery(ability, 'read', 'Subject')).toThrow(ForbiddenError); + }); + + // `ability.can` refuses here, since CASL 7 reads a cannot rule matching everything as unconditional, + // but the query is a filter that matches nothing, which is what @casl/prisma 1 returned too. + it('should filter rather than throw when a cannot rule matching everything outranks a can rule', () => { + const ability = createAppAbility([ + { action: 'read', conditions: { groupIds: { hasSome: ['group-1'] } }, subject: 'Subject' }, + { action: 'read', conditions: {}, inverted: true, subject: 'Subject' } + ]); + expect(ability.can('read', 'Subject')).toBe(false); + expect(accessibleQuery(ability, 'read', 'Subject')).toStrictEqual({ + OR: [{ AND: [{ groupIds: { hasSome: ['group-1'] } }, { NOT: {} }] }] }); - const ability = vi.fn(); - expect(accessibleQuery(ability as any, 'manage', 'User')).toStrictEqual('QUERY'); - expect(accessibleBy).toHaveBeenCalledExactlyOnceWith(ability, 'manage'); }); }); diff --git a/apps/api/src/auth/ability.utils.ts b/apps/api/src/auth/ability.utils.ts index 1e7888251..e10306e69 100644 --- a/apps/api/src/auth/ability.utils.ts +++ b/apps/api/src/auth/ability.utils.ts @@ -1,14 +1,10 @@ -import { detectSubjectType, subject } from '@casl/ability'; -import { createPrismaAbility } from '@casl/prisma'; -import type { PrismaQuery } from '@casl/prisma'; -import { createAccessibleByFactory } from '@casl/prisma/runtime'; +import { detectSubjectType, ForbiddenError, subject } from '@casl/ability'; +import { accessibleBy, createPrismaAbility } from '@casl/prisma'; import type { AppSubject, Prisma } from '@prisma/client'; import type { PrismaModelWhereInputMap } from '@/core/prisma'; -import type { AppAbilities, AppAbility, AppAction, AppSubjectModels, AppSubjectName, Permission } from './auth.types'; - -const accessibleBy = createAccessibleByFactory(); +import type { AppAbility, AppAction, AppSubjectModels, AppSubjectName, Permission } from './auth.types'; export function detectAppSubject(obj: { [key: string]: any }) { if (typeof obj.__modelName === 'string') { @@ -28,7 +24,7 @@ export function forcedAppSubject(permissions, { + return createPrismaAbility(permissions, { detectSubjectType: detectAppSubject }); } @@ -41,5 +37,15 @@ export function accessibleQuery( if (!ability) { return {}; } - return accessibleBy(ability, action)[modelName]!; + const query = accessibleBy(ability, action).ofType(modelName); + // `ofType` returns `{ OR: [] }` exactly when no rule grants the action on the model, which is when + // @casl/prisma 1 threw this error. Prisma ignores an empty `OR` nested in an `AND` + // (prisma/prisma#17367), so passing it on would lift the restriction instead of applying it. + if (query.OR?.length === 0) { + const error = ForbiddenError.from(ability).setMessage(`It's not allowed to run "${action}" on "${modelName}"`); + error.action = action; + error.subject = error.subjectType = modelName; + throw error; + } + return query; } diff --git a/apps/api/src/auth/auth.types.ts b/apps/api/src/auth/auth.types.ts index 2663f77b5..36c5d25b2 100644 --- a/apps/api/src/auth/auth.types.ts +++ b/apps/api/src/auth/auth.types.ts @@ -1,5 +1,4 @@ -import { PureAbility } from '@casl/ability'; -import type { RawRuleOf } from '@casl/ability'; +import type { Ability, RawRuleOf } from '@casl/ability'; import type { PrismaQuery, Subjects } from '@casl/prisma'; import { Prisma } from '@prisma/client'; import type { DefaultSelection } from '@prisma/client/runtime/library'; @@ -16,8 +15,8 @@ type AppSubjectName = Extract; type AppAbilities = [AppAction, AppSubjects]; -type AppAbility = PureAbility; +type AppAbility = Ability; -type Permission = RawRuleOf>; +type Permission = RawRuleOf>; -export type { AppAbilities, AppAbility, AppAction, AppSubjectModels, AppSubjectName, Permission }; +export type { AppAbility, AppAction, AppSubjectModels, AppSubjectName, Permission }; diff --git a/apps/api/src/auth/guards/jwt-auth.guard.ts b/apps/api/src/auth/guards/jwt-auth.guard.ts index 486f8f06b..37a02e78c 100644 --- a/apps/api/src/auth/guards/jwt-auth.guard.ts +++ b/apps/api/src/auth/guards/jwt-auth.guard.ts @@ -1,4 +1,4 @@ -import { PureAbility } from '@casl/ability'; +import { Ability } from '@casl/ability'; import { LoggingService } from '@douglasneuroinformatics/libnest'; import { Injectable, InternalServerErrorException } from '@nestjs/common'; import type { ExecutionContext } from '@nestjs/common'; @@ -55,7 +55,7 @@ export class JwtAuthGuard extends AuthGuard('jwt') { const ability = request.user?.ability; - if (!(ability instanceof PureAbility)) { + if (!(ability instanceof Ability)) { this.loggingService.error('User property of request does not include expected AppAbility'); throw new InternalServerErrorException(); } diff --git a/apps/api/src/demo/__tests__/demo.service.test.ts b/apps/api/src/demo/__tests__/demo.service.test.ts index 4676915e4..d494f0c2b 100644 --- a/apps/api/src/demo/__tests__/demo.service.test.ts +++ b/apps/api/src/demo/__tests__/demo.service.test.ts @@ -6,6 +6,7 @@ import { InternalServerErrorException } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { DEMO_GROUPS, DEMO_USERS } from '@opendatacapture/demo'; import type { $CreateGroupData } from '@opendatacapture/schemas/group'; +import { $Sex } from '@opendatacapture/schemas/subject'; import { encodeScopedSubjectId, generateSubjectHash } from '@opendatacapture/subject-utils'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; @@ -149,6 +150,12 @@ describe('DemoService', () => { expect(subject.id).toBe(await generateSubjectHash({ dateOfBirth, firstName, lastName, sex })); }); + it('should draw dummy subjects from every sex the subject schema accepts and no other', async () => { + await demoService.init({ dummySubjectCount: 20, recordsPerSubject: 0 }); + const sexes = subjectsService.create.mock.calls.map(([subject]) => subject.sex); + expect(new Set(sexes)).toStrictEqual(new Set($Sex.options)); + }); + it('should number dummy subjects in a custom-id group in sequence under the group prefix', async () => { vi.spyOn(Math, 'random').mockReturnValue(LAST_GROUP); await demoService.init({ dummySubjectCount: 2, recordsPerSubject: 0 }); diff --git a/apps/api/src/demo/demo.service.ts b/apps/api/src/demo/demo.service.ts index dbea5f795..01e6cb00c 100644 --- a/apps/api/src/demo/demo.service.ts +++ b/apps/api/src/demo/demo.service.ts @@ -1,4 +1,4 @@ -import { randomValue, toUpperCase } from '@douglasneuroinformatics/libjs'; +import { randomValue } from '@douglasneuroinformatics/libjs'; import { InjectPrismaClient, LoggingService } from '@douglasneuroinformatics/libnest'; import { faker } from '@faker-js/faker'; import { Injectable, InternalServerErrorException } from '@nestjs/common'; @@ -14,6 +14,7 @@ import happinessQuestionnaireWithConsent from '@opendatacapture/instrument-libra import type { FormInstrument, Language } from '@opendatacapture/runtime-core'; import type { WithID } from '@opendatacapture/schemas/core'; import type { Group } from '@opendatacapture/schemas/group'; +import { $Sex } from '@opendatacapture/schemas/subject'; import { encodeScopedSubjectId, generateSubjectHash } from '@opendatacapture/subject-utils'; import type { RuntimePrismaClient } from '@/core/prisma'; @@ -106,7 +107,7 @@ export class DemoService { dateOfBirth: faker.date.birthdate(), firstName: faker.person.firstName(), lastName: faker.person.lastName(), - sex: toUpperCase(faker.person.sexType()) + sex: faker.helpers.arrayElement($Sex.options) }; let subjectId: string; diff --git a/apps/api/src/instrument-records/instrument-records.service.ts b/apps/api/src/instrument-records/instrument-records.service.ts index 18355776c..6fa7e3788 100644 --- a/apps/api/src/instrument-records/instrument-records.service.ts +++ b/apps/api/src/instrument-records/instrument-records.service.ts @@ -480,7 +480,7 @@ export class InstrumentRecordsService { // Only the rows this call wrote. Filtering by instrument alone returned every group's records // when `groupId` was omitted, and `accessibleQuery` cannot scope this read: a STANDARD uploader - // holds no `read InstrumentRecord` rule, which makes CASL throw rather than filter. + // holds no `read InstrumentRecord` rule, which makes `accessibleQuery` throw rather than filter. return this.instrumentRecordModel.findMany({ where: { sessionId: { in: sessions.map((session) => session.id) } diff --git a/apps/api/vitest.config.ts b/apps/api/vitest.config.ts index 8c09a176c..36464b388 100644 --- a/apps/api/vitest.config.ts +++ b/apps/api/vitest.config.ts @@ -4,7 +4,7 @@ import libnest from '@douglasneuroinformatics/libnest/testing/plugin'; import { defineProject, mergeConfig } from 'vitest/config'; import type { Plugin } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; const [swcPlugin, libnestPlugin] = libnest({ baseUrl: path.resolve(import.meta.dirname, 'src'), @@ -15,10 +15,10 @@ const [swcPlugin, libnestPlugin] = libnest({ const apiFilePattern = new RegExp(`^${(import.meta.dirname + path.sep).replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`); -// libnest exposes no include option and its SWC plugin disables esbuild outright, so SWC would also -// transform the workspace packages this project imports. SWC source maps place functions differently -// from the esbuild transform every other project uses, which makes merged coverage count each of those -// functions twice, with one copy never hit. SWC is only needed for the decorators in this app. +// libnest exposes no include option and its SWC plugin tries to disable the default transform, so SWC +// would also transform the workspace packages this project imports. SWC source maps place functions +// differently from the Oxc transform every other project uses, which makes merged coverage count each +// of those functions twice, with one copy never hit. SWC is only needed for the decorators in this app. const apiOnlySwcPlugin: Plugin = { ...swcPlugin, config: undefined, @@ -33,7 +33,7 @@ const apiOnlySwcPlugin: Plugin = { export default mergeConfig( baseConfig, defineProject({ - esbuild: { + oxc: { exclude: [/\.js$/, apiFilePattern] }, plugins: [apiOnlySwcPlugin, libnestPlugin], diff --git a/apps/gateway/package.json b/apps/gateway/package.json index 96e9f8ccc..e640d51f0 100644 --- a/apps/gateway/package.json +++ b/apps/gateway/package.json @@ -18,7 +18,7 @@ "start": "NODE_ENV=production env-cmd -f ../../.env node dist/main.js" }, "dependencies": { - "@cap.js/server": "^2.0.0", + "@cap.js/server": "^4.0.5", "@cap.js/widget": "^0.1.58", "@douglasneuroinformatics/libcrypto": "catalog:", "@douglasneuroinformatics/libui": "catalog:", diff --git a/apps/gateway/src/routers/__tests__/cap.router.test.ts b/apps/gateway/src/routers/__tests__/cap.router.test.ts index 293ec4a91..5c38e3190 100644 --- a/apps/gateway/src/routers/__tests__/cap.router.test.ts +++ b/apps/gateway/src/routers/__tests__/cap.router.test.ts @@ -1,5 +1,6 @@ import type { Server } from 'http'; +import type Cap from '@cap.js/server'; import express from 'express'; import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; @@ -10,12 +11,14 @@ import { $VerifyRequest, capRouter } from '../cap.router'; const { cap } = vi.hoisted(() => ({ cap: { - createChallenge: vi.fn(), - redeemChallenge: vi.fn(), - validateToken: vi.fn() + createChallenge: vi.fn(), + redeemChallenge: vi.fn(), + validateToken: vi.fn() } })); +const challenge = { challenge: { c: 1, d: 4, s: 2 }, expires: 1_000, token: 'challenge-token' }; + vi.mock('@/lib/cap', () => ({ cap })); vi.mock('@/logger', () => ({ logger: { error: vi.fn() } })); @@ -64,11 +67,16 @@ describe('$VerifyRequest', () => { }); describe('POST /challenge', () => { - it('should issue a challenge that expires in five minutes, so a stale challenge cannot be solved later', async () => { - cap.createChallenge.mockReturnValueOnce({ challenge: { c: 1, d: 4, s: 2 }, token: 'challenge-token' }); + it('should respond with the challenge Cap resolves, not the pending promise, so the widget has a challenge to solve', async () => { + cap.createChallenge.mockResolvedValueOnce(challenge); const response = await post('/challenge', {}); expect(response.status).toBe(200); - expect(await response.json()).toEqual({ challenge: { c: 1, d: 4, s: 2 }, token: 'challenge-token' }); + expect(await response.json()).toEqual(challenge); + }); + + it('should issue a challenge that expires in five minutes, so a stale challenge cannot be solved later', async () => { + cap.createChallenge.mockResolvedValueOnce(challenge); + await post('/challenge', {}); expect(cap.createChallenge).toHaveBeenCalledWith({ challengeDifficulty: 4, expiresMs: 300_000 }); }); }); diff --git a/apps/gateway/src/routers/cap.router.ts b/apps/gateway/src/routers/cap.router.ts index ec9034d96..e01cd58ff 100644 --- a/apps/gateway/src/routers/cap.router.ts +++ b/apps/gateway/src/routers/cap.router.ts @@ -25,14 +25,17 @@ const $VerifyRequest = z.object({ const router = Router(); -router.post('/challenge', (_, res) => { - res.status(200).json( - cap.createChallenge({ - challengeDifficulty: 4, - expiresMs: 60_000 * 5 - }) - ); -}); +router.post( + '/challenge', + ah(async (_, res) => { + res.status(200).json( + await cap.createChallenge({ + challengeDifficulty: 4, + expiresMs: 60_000 * 5 + }) + ); + }) +); router.post( '/redeem', diff --git a/apps/gateway/src/server/__tests__/server.development.test.ts b/apps/gateway/src/server/__tests__/server.development.test.ts index 43cd79c85..9360812ce 100644 --- a/apps/gateway/src/server/__tests__/server.development.test.ts +++ b/apps/gateway/src/server/__tests__/server.development.test.ts @@ -2,7 +2,7 @@ import { once } from 'events'; import fs from 'fs'; import type { Server } from 'http'; -import { afterAll, afterEach, describe, expect, it, vi } from 'vitest'; +import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from 'vitest'; import { config } from '@/config'; import type { RenderFunction } from '@/entry-server'; @@ -60,6 +60,12 @@ class TestDevelopmentServer extends DevelopmentServer { const openServers: Server[] = []; +let createServerCalls: unknown[][]; + +beforeAll(() => { + createServerCalls = [...createServer.mock.calls]; +}); + afterEach(async () => { await Promise.all( openServers.splice(0).map((httpServer) => { @@ -78,7 +84,7 @@ afterAll(() => { describe('DevelopmentServer', () => { it('should create vite in middleware mode, so express stays in charge of the http server', () => { - expect(createServer).toHaveBeenCalledWith({ appType: 'custom', server: { middlewareMode: true } }); + expect(createServerCalls).toStrictEqual([[{ appType: 'custom', server: { middlewareMode: true } }]]); }); it('should mount the vite middlewares, so client assets are served with hot reload', async () => { diff --git a/apps/gateway/vite.config.ts b/apps/gateway/vite.config.ts index 47aeafdc3..b860ad626 100644 --- a/apps/gateway/vite.config.ts +++ b/apps/gateway/vite.config.ts @@ -13,8 +13,10 @@ export default defineConfig(({ mode }) => ({ target: 'es2022' }, optimizeDeps: { - esbuildOptions: { - target: 'es2022' + rolldownOptions: { + transform: { + target: 'es2022' + } }, include: ['react/*', 'react-dom/*'] }, diff --git a/apps/gateway/vitest.config.ts b/apps/gateway/vitest.config.ts index 3eb07a276..ef65e1631 100644 --- a/apps/gateway/vitest.config.ts +++ b/apps/gateway/vitest.config.ts @@ -2,7 +2,7 @@ import path from 'path'; import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/apps/outreach/AGENTS.md b/apps/outreach/AGENTS.md index 4b811308f..c937f1a4b 100644 --- a/apps/outreach/AGENTS.md +++ b/apps/outreach/AGENTS.md @@ -55,6 +55,14 @@ group there. `lib/index.d.ts` on every build, so hand edits are lost. To change that API reference, change runtime-core's TSDoc. Background: `.agents/docs/architecture/runtime-and-vendor.md`. +The plugin is a fork of upstream `starlight-typedoc`, built on typedoc's router: the sidebar comes from +the page URLs typedoc reports at `RendererEvent.END`, and `theme.ts` overrides `urlTo` to emit +absolute Starlight links. `router.ts` keeps namespaces exported from the package root at +`namespaces//`; typedoc-plugin-markdown's member router would nest them under +`@opendatacapture/`, which moves their URLs and drops the Namespaces sidebar group. After upgrading +typedoc or typedoc-plugin-markdown, build before and after and diff the generated directory, its +links and anchors, and the sidebar. + ## Content collections Config is `src/content/config.ts` — the legacy Astro path, **not** `src/content.config.ts`. The diff --git a/apps/outreach/package.json b/apps/outreach/package.json index 3e39b5de7..085800ee8 100644 --- a/apps/outreach/package.json +++ b/apps/outreach/package.json @@ -35,7 +35,7 @@ "github-slugger": "^2.0.0", "sharp": "^0.34.5", "tailwindcss": "catalog:", - "typedoc": "0.27.x", - "typedoc-plugin-markdown": "4.4.x" + "typedoc": "^0.28.20", + "typedoc-plugin-markdown": "^4.13.1" } } diff --git a/apps/outreach/src/plugins/starlight-plugin-typedoc/index.ts b/apps/outreach/src/plugins/starlight-plugin-typedoc/index.ts index eb47e903e..73f02d20b 100644 --- a/apps/outreach/src/plugins/starlight-plugin-typedoc/index.ts +++ b/apps/outreach/src/plugins/starlight-plugin-typedoc/index.ts @@ -47,12 +47,13 @@ export function starlightTypeDocPlugin(options: StarlightTypeDocOptions): Starli return { hooks: { async setup({ astroConfig, config, logger, updateConfig }) { - const { baseOutputDirectory, reflections } = await generateTypeDoc(options, astroConfig, logger); + const { baseOutputDirectory, pageUrls, reflections } = await generateTypeDoc(options, astroConfig, logger); const sidebar = getSidebarFromReflections( config.sidebar, starlightTypeDocSidebarGroup, options.sidebar, reflections, + pageUrls, baseOutputDirectory ); updateConfig({ sidebar }); diff --git a/apps/outreach/src/plugins/starlight-plugin-typedoc/router.ts b/apps/outreach/src/plugins/starlight-plugin-typedoc/router.ts new file mode 100644 index 000000000..bc6552e6b --- /dev/null +++ b/apps/outreach/src/plugins/starlight-plugin-typedoc/router.ts @@ -0,0 +1,16 @@ +import { ReflectionKind } from 'typedoc'; +import type { Reflection } from 'typedoc'; +import { MemberRouter } from 'typedoc-plugin-markdown'; + +/** + * typedoc-plugin-markdown's member router places a namespace exported from the project root under a directory + * named after the project (`@opendatacapture/namespaces/...`), unlike every other root export. + */ +export class StarlightTypeDocRouter extends MemberRouter { + override getIdealBaseName(reflection: Reflection): string { + if (reflection.kindOf(ReflectionKind.Namespace) && reflection.parent?.isProject()) { + return `namespaces/${this.getReflectionAlias(reflection)}/${this.entryFileName}`; + } + return super.getIdealBaseName(reflection); + } +} diff --git a/apps/outreach/src/plugins/starlight-plugin-typedoc/starlight.ts b/apps/outreach/src/plugins/starlight-plugin-typedoc/starlight.ts index 008609dbf..d429df3cd 100644 --- a/apps/outreach/src/plugins/starlight-plugin-typedoc/starlight.ts +++ b/apps/outreach/src/plugins/starlight-plugin-typedoc/starlight.ts @@ -5,7 +5,7 @@ import path from 'node:path'; import type { StarlightPlugin } from '@astrojs/starlight/types'; import { slug } from 'github-slugger'; import { ReferenceReflection, ReflectionKind } from 'typedoc'; -import type { DeclarationReflection, ProjectReflection, ReflectionGroup } from 'typedoc'; +import type { DeclarationReflection, ProjectReflection, ReflectionGroup, RouterTarget } from 'typedoc'; import type { StarlightTypeDocSidebarOptions } from './index'; @@ -25,13 +25,20 @@ export function getSidebarFromReflections( sidebarGroupPlaceholder: SidebarGroup, options: StarlightTypeDocSidebarOptions, reflections: DeclarationReflection | ProjectReflection, + pageUrls: PageUrls, baseOutputDirectory: string ): StarlightUserConfigSidebar { if (!sidebar || sidebar.length === 0) { return sidebar; } - const sidebarGroup = getSidebarGroupFromReflections(options, reflections, baseOutputDirectory, baseOutputDirectory); + const sidebarGroup = getSidebarGroupFromReflections( + options, + reflections, + pageUrls, + baseOutputDirectory, + baseOutputDirectory + ); function replaceSidebarGroupPlaceholder(group: SidebarManualGroup): SidebarGroup { if (group.label === sidebarGroupPlaceholder.label) { @@ -58,18 +65,22 @@ export function getSidebarFromReflections( function getSidebarGroupFromPackageReflections( options: StarlightTypeDocSidebarOptions, reflections: DeclarationReflection | ProjectReflection, + pageUrls: PageUrls, baseOutputDirectory: string ): SidebarGroup { const groups = (reflections.children ?? []).map((child) => { - if (!child.url) { + const childUrl = pageUrls.get(child); + + if (!childUrl) { return undefined; } - const url = path.parse(child.url); + const url = path.parse(childUrl); return getSidebarGroupFromReflections( options, child, + pageUrls, baseOutputDirectory, `${baseOutputDirectory}/${url.dir}`, child.name @@ -86,12 +97,13 @@ function getSidebarGroupFromPackageReflections( function getSidebarGroupFromReflections( options: StarlightTypeDocSidebarOptions, reflections: DeclarationReflection | ProjectReflection, + pageUrls: PageUrls, baseOutputDirectory: string, outputDirectory: string, label?: string ): SidebarGroup { if ((!reflections.groups || reflections.groups.length === 0) && reflections.children) { - return getSidebarGroupFromPackageReflections(options, reflections, outputDirectory); + return getSidebarGroupFromPackageReflections(options, reflections, pageUrls, outputDirectory); } const groups = reflections.groups ?? []; @@ -102,16 +114,19 @@ function getSidebarGroupFromReflections( .flatMap((group) => { if (group.title === 'Modules') { return group.children.map((child) => { - if (!child.url) { + const childUrl = pageUrls.get(child); + + if (!childUrl) { return undefined; } - const url = path.parse(child.url); + const url = path.parse(childUrl); const isParentKindModule = child.parent?.kind === ReflectionKind.Module; return getSidebarGroupFromReflections( { collapsed: true, label: child.name }, child as DeclarationReflection, + pageUrls, baseOutputDirectory, `${outputDirectory}/${isParentKindModule ? url.dir.split('/').slice(1).join('/') : url.dir}` ); @@ -119,14 +134,14 @@ function getSidebarGroupFromReflections( } if (isReferenceReflectionGroup(group)) { - return getReferencesSidebarGroup(group, baseOutputDirectory); + return getReferencesSidebarGroup(group, pageUrls, baseOutputDirectory); } const directory = `${outputDirectory}/${slug(group.title.toLowerCase())}`; // The groups generated using the `@group` tag do not have an associated directory on disk. const isGroupWithDirectory = group.children.some((child) => - path.posix.join(baseOutputDirectory, child.url?.replace('\\', '/') ?? '').startsWith(directory) + path.posix.join(baseOutputDirectory, pageUrls.get(child)?.replace('\\', '/') ?? '').startsWith(directory) ); if (!isGroupWithDirectory) { @@ -149,6 +164,7 @@ function getSidebarGroupFromReflections( function getReferencesSidebarGroup( group: ReflectionGroup, + pageUrls: PageUrls, baseOutputDirectory: string ): SidebarManualGroup | undefined { const referenceItems: LinkItem[] = group.children @@ -164,13 +180,15 @@ function getReferencesSidebarGroup( target = target.parent; } - if (!target.url) { + const targetUrl = pageUrls.get(target); + + if (!targetUrl) { return undefined; } return { label: reference.name, - link: getRelativeURL(target.url, getStarlightTypeDocOutputDirectory(baseOutputDirectory)) + link: getRelativeURL(targetUrl, getStarlightTypeDocOutputDirectory(baseOutputDirectory)) }; }) .filter((item): item is LinkItem => item !== undefined); @@ -260,4 +278,6 @@ type LinkItem = { type AsideType = 'caution' | 'danger' | 'note' | 'tip'; +type PageUrls = ReadonlyMap; + type StarlightUserConfigSidebar = Parameters>[0]['config']['sidebar']; diff --git a/apps/outreach/src/plugins/starlight-plugin-typedoc/theme.ts b/apps/outreach/src/plugins/starlight-plugin-typedoc/theme.ts index 58faa97ad..08515fd7e 100644 --- a/apps/outreach/src/plugins/starlight-plugin-typedoc/theme.ts +++ b/apps/outreach/src/plugins/starlight-plugin-typedoc/theme.ts @@ -1,5 +1,3 @@ -import path from 'node:path'; - import { Reflection } from 'typedoc'; import type { Comment, CommentDisplayPart, Options } from 'typedoc'; import { MarkdownPageEvent, MarkdownTheme, MarkdownThemeContext } from 'typedoc-plugin-markdown'; @@ -31,13 +29,11 @@ class StarlightTypeDocThemeRenderContext extends MarkdownThemeContext { part.kind === 'inline-tag' && (part.tag === '@link' || part.tag === '@linkcode' || part.tag === '@linkplain') && part.target instanceof Reflection && - typeof part.target.url === 'string' + this.router.hasUrl(part.target) ) { return { ...part, - target: this.getRelativeUrl( - path.posix.join(this.options.getValue('entryPointStrategy') === 'packages' ? '../..' : '..', part.target.url) - ) + target: this.urlTo(part.target) }; } @@ -109,11 +105,11 @@ class StarlightTypeDocThemeRenderContext extends MarkdownThemeContext { this.#markdownThemeContext = new MarkdownThemeContext(theme, event, options); } - override getRelativeUrl(url: string): string { + override urlTo(reflection: Reflection): string { const outputDirectory = this.options.getValue('starlight-typedoc-output'); const baseUrl = typeof outputDirectory === 'string' ? outputDirectory : ''; - return getRelativeURL(url, baseUrl, this.page.url); + return getRelativeURL(this.router.getFullUrl(reflection), baseUrl, this.page.url); } #addAside(markdown: string, ...args: Parameters) { diff --git a/apps/outreach/src/plugins/starlight-plugin-typedoc/typedoc.ts b/apps/outreach/src/plugins/starlight-plugin-typedoc/typedoc.ts index 6d6597bd7..7a541f2cc 100644 --- a/apps/outreach/src/plugins/starlight-plugin-typedoc/typedoc.ts +++ b/apps/outreach/src/plugins/starlight-plugin-typedoc/typedoc.ts @@ -4,11 +4,12 @@ import url from 'node:url'; import type { AstroConfig, AstroIntegrationLogger } from 'astro'; import { Application, PageEvent, ParameterType, RendererEvent } from 'typedoc'; -import type { Reflection, TypeDocOptions } from 'typedoc'; +import type { RouterTarget, TypeDocOptions } from 'typedoc'; import type { MarkdownPageEvent, PluginOptions } from 'typedoc-plugin-markdown'; import { StarlightTypeDocLogger } from './logger'; import { addFrontmatter } from './markdown'; +import { StarlightTypeDocRouter } from './router'; import { getStarlightTypeDocOutputDirectory } from './starlight'; import { StarlightTypeDocTheme } from './theme'; @@ -20,6 +21,7 @@ const defaultTypeDocConfig: TypeDocConfig = { excludeProtected: true, githubPages: false, readme: 'none', + router: 'starlight-typedoc', theme: 'starlight-typedoc' }; @@ -32,8 +34,24 @@ const markdownPluginConfig: TypeDocConfig = { async function generateTypeDoc(options: StarlightTypeDocOptions, config: AstroConfig, logger: AstroIntegrationLogger) { const baseOutputDirectory = options.output; const outputDirectory = `${options.locale}/${baseOutputDirectory}`; + const outputPath = path.join(url.fileURLToPath(config.srcDir), 'content/docs', outputDirectory); + + const app = await bootstrapApp( + options.entryPoints, + options.tsconfig, + outputDirectory, + outputPath, + config.base, + logger + ); + + const pageUrls = new Map(); + app.renderer.on(RendererEvent.END, ({ pages }) => { + for (const page of pages) { + pageUrls.set(page.model, page.url); + } + }); - const app = await bootstrapApp(options.entryPoints, options.tsconfig, outputDirectory, config.base, logger); const reflections = await app.convert(); if ( @@ -43,17 +61,16 @@ async function generateTypeDoc(options: StarlightTypeDocOptions, config: AstroCo throw new Error('Failed to generate TypeDoc documentation.'); } - const outputPath = path.join(url.fileURLToPath(config.srcDir), 'content/docs', outputDirectory); - - await app.generateDocs(reflections, outputPath); + await app.generateOutputs(reflections); - return { baseOutputDirectory, reflections }; + return { baseOutputDirectory, pageUrls, reflections }; } async function bootstrapApp( entryPoints: TypeDocOptions['entryPoints'], tsconfig: TypeDocOptions['tsconfig'], outputDirectory: string, + outputPath: string, base: string, logger: AstroIntegrationLogger ) { @@ -63,17 +80,18 @@ async function bootstrapApp( ...defaultTypeDocConfig, ...markdownPluginConfig, entryPoints, + outputs: [{ name: 'markdown', path: outputPath }], plugin: ['typedoc-plugin-markdown'], tsconfig }); app.logger = new StarlightTypeDocLogger(logger); - // @ts-expect-error - inherited code + app.renderer.defineRouter('starlight-typedoc', StarlightTypeDocRouter); app.renderer.defineTheme('starlight-typedoc', StarlightTypeDocTheme); - app.renderer.on(PageEvent.BEGIN, (event: PageEvent) => { + app.renderer.on(PageEvent.BEGIN, (event) => { // @ts-expect-error - inherited code onRendererPageBegin(event); }); - app.renderer.on(PageEvent.END, (event: PageEvent) => { + app.renderer.on(PageEvent.END, (event) => { // @ts-expect-error - inherited code const shouldRemovePage = onRendererPageEnd(event); if (shouldRemovePage) { diff --git a/apps/playground/AGENTS.md b/apps/playground/AGENTS.md index 23f299117..ecf459ba2 100644 --- a/apps/playground/AGENTS.md +++ b/apps/playground/AGENTS.md @@ -8,25 +8,45 @@ Read the root `AGENTS.md` first for the rules that apply everywhere. ## Top-level await is load-bearing -Two modules do real work at import time, and both are fragile. - -- **`src/pages/IndexPage.tsx`** calls `await initialize({ wasmURL })` from `esbuild-wasm` above the - component. esbuild-wasm throws `Cannot call "initialize" more than once` on a second call, so this - must stay in exactly one module. `src/App.tsx` reaches it through `React.lazy`, which is what puts - the 13 MB `esbuild.wasm` download behind the Suspense fallback. Importing `IndexPage` eagerly, or - adding a second `initialize()`, breaks the app at boot. -- **`src/components/Editor/setup.ts`** configures Monaco (workers, compiler options, themes, prettier - as the formatter) inside a top-level `await loader.init()` block. `Editor.tsx` pulls it in with a - bare `import './setup'` for the side effect. - -Both depend on `build.target` and `optimizeDeps.esbuildOptions.target` being `es2022` in +**`src/pages/IndexPage.tsx`** calls `await initialize({ wasmURL })` from `esbuild-wasm` above the +component. esbuild-wasm throws `Cannot call "initialize" more than once` on a second call, so this +must stay in exactly one module. `src/App.tsx` reaches it through `React.lazy`, which is what puts +the 13 MB `esbuild.wasm` download behind the Suspense fallback. Importing `IndexPage` eagerly, or +adding a second `initialize()`, breaks the app at boot. + +It depends on `build.target` and `optimizeDeps.rolldownOptions.transform.target` being `es2022` in `vite.config.ts`. Lowering either one is how top-level await silently stops compiling. -`rollupOptions.external: ['esbuild']` is also required. `packages/instrument-bundler/src/vendor/esbuild.ts` +`build.rolldownOptions.external: ['esbuild']` is also required. `packages/instrument-bundler/src/vendor/esbuild.ts` picks between `esbuild` and `esbuild-wasm` on `typeof window`; without the external, Vite tries to pull the Node package into the browser bundle. Background: `.agents/docs/architecture/runtime-and-vendor.md`. +## Monaco is wired up by hand + +**`src/components/Editor/setup.ts` configures Monaco at import time** — workers, compiler options, +themes, prettier as the formatter. `Editor.tsx` pulls it in with a bare `import './setup'` for the +side effect, so it has run before any editor exists. + +**`src/components/Editor/MonacoEditor.tsx` is the editor component**, in place of +`@monaco-editor/react`, whose 4.7 types import `monaco-editor/esm/vs/editor/editor.api`, a path the +`exports` map `monaco-editor` 0.56 added no longer resolves. It keeps one model per `path` and never +disposes one: `EditorPane` is keyed by instrument and filename, so every file switch remounts the +editor, and the surviving model is what keeps the file's content and undo history. It restores each +model's cursor and scroll position on the way back. Only `EditorPane` disposes models: all of them, +on an instrument switch or when it unmounts. + +**Deep imports go through that `exports` map**, which sends `monaco-editor/` to +`esm/vs/.js`. The language workers come from +`monaco-editor/languages/features//.worker`; the `esm/vs/language/*` paths the +Monaco docs still show are deprecated re-exports. `SuggestAdapter` comes from +`monaco-editor/languages/features/typescript/tsMode`, an internal module with no types of its own, +declared in `src/typings/monaco-editor.d.ts`. `setup.ts` switches off the built-in completion +provider (`completionItems: false`) and registers a subclass whose only change is quotes as trigger +characters, so string-literal completions open as you type. The TypeScript API is the top-level +`monaco.typescript` namespace; `monaco.languages.typescript` has been an empty `{ deprecated: true }` +since 0.57. + ## Running it `pnpm dev` at the repo root does **not** start the playground — `dev:core` filters to api, gateway and @@ -39,7 +59,7 @@ degraded experience. `tsc` needs it too: the tsconfig maps `/runtime/v1/*` to `. which is the only reason example instruments importing `/runtime/v1/zod@3.x` type-check. `build.emptyOutDir` is `false` on purpose. The runtime plugin copies the runtime into -`dist/runtime/` from `buildStart`, and Vite empties the output directory _after_ the rollup +`dist/runtime/` from `buildStart`, and Vite empties the output directory _after_ the Rolldown build finishes. The cost is that `dist/` accumulates stale files — delete it by hand when a build looks wrong. @@ -150,6 +170,11 @@ directly means pasting a second share link into an open tab does nothing. Its `$ `.vscode/Scratch/` is unrelated junk. +The editor/preview split in `src/components/MainContent/MainContent.tsx` gives every +`react-resizable-panels` size as a percentage string. Version 4 reads a bare number as pixels, so +`defaultSize={66}` still type-checks and renders, at the wrong size; the split test in +`testing/src/specs/playground.spec.ts` measures the panes to catch it. + `__APP_VERSION__` and `__GITHUB_REPO_URL__` are the build-time defines, declared in `src/vite-env.d.ts` and supplied in `vite.config.ts`; `GITHUB_REPO_URL` must be listed under the `build` task's `env` in `turbo.json` or turbo's strict env mode hides it from the build. Anything @@ -157,12 +182,18 @@ that differs between deployments belongs in `/config.json` instead. ## Tests -`pnpm exec vitest --project playground`, from the repo root. The project runs in node and covers -only what is pure — `src/preview/__tests__/protocol.test.ts` pins the message schemas, error -serialization and `resolvePreviewOrigin`, and `config.test.ts` the `/config.json` contract. -Anything that touches esbuild-wasm, Monaco workers or `/runtime/v1` has no test environment here; -the frame itself, the origin split, the runtime config and the message bridge are exercised for real -by `testing/src/specs/playground.spec.ts`, which Playwright runs against this app's dev server. +`pnpm exec vitest --project playground`, from the repo root. The project runs in node, with no DOM, +and covers only what is pure — `src/preview/__tests__/protocol.test.ts` pins the message schemas, +error serialization and `resolvePreviewOrigin`, and `config.test.ts` the `/config.json` contract. A +component that renders on a server can still be pinned through `react-dom/server`'s +`renderToStaticMarkup`, as `src/components/Resizable/__tests__/` does for the attributes its classes +key on. A component test that needs a DOM opts in per file with a `// @vitest-environment happy-dom` +docblock on its first line and renders with `@testing-library/react`; +`src/components/Editor/__tests__/MonacoEditor.test.tsx` does, against a mocked `monaco-editor`, +because Monaco itself does not run under happy-dom. Anything that touches esbuild-wasm, Monaco +workers or `/runtime/v1` has no test environment here; the frame itself, the origin split, the runtime config, the message bridge and the resizable +editor/preview split are exercised for real by `testing/src/specs/playground.spec.ts`, which +Playwright runs against this app's dev server. Storybook collects `*.stories.tsx` under `src/components/` centrally through `storybook/config/main.ts` under the `Playground Components` prefix. See diff --git a/apps/playground/package.json b/apps/playground/package.json index 4aa64be0f..e385b1a36 100644 --- a/apps/playground/package.json +++ b/apps/playground/package.json @@ -16,7 +16,6 @@ "@douglasneuroinformatics/libcrypto": "catalog:", "@douglasneuroinformatics/libjs": "catalog:", "@douglasneuroinformatics/libui": "catalog:", - "@monaco-editor/react": "^4.7.0", "@opendatacapture/instrument-bundler": "workspace:*", "@opendatacapture/playground-url": "workspace:*", "@opendatacapture/react-core": "workspace:*", @@ -31,15 +30,15 @@ "jszip": "^3.10.2", "jwt-decode": "^4.0.0", "lodash-es": "workspace:lodash-es__4.x@*", - "lucide-react": "^0.577.0", - "monaco-editor": "^0.54.0", + "lucide-react": "^1.49.0", + "monaco-editor": "^0.57.0", "motion": "catalog:", "neverthrow": "catalog:", "react": "workspace:react__19.x@*", "react-dom": "workspace:react-dom__19.x@*", "react-dropzone": "catalog:", "react-error-boundary": "^6.1.6", - "react-resizable-panels": "^3.0.6", + "react-resizable-panels": "^4.14.1", "ts-pattern": "workspace:ts-pattern__5.x@*", "zod": "workspace:zod__3.x@*", "zustand": "catalog:" @@ -48,7 +47,10 @@ "@opendatacapture/vite-plugin-runtime": "workspace:*", "@storybook/react-vite": "catalog:", "@tailwindcss/vite": "catalog:", + "@testing-library/dom": "catalog:", + "@testing-library/react": "catalog:", "@vitejs/plugin-react-swc": "^4.3.3", + "happy-dom": "catalog:", "tailwindcss": "catalog:", "type-fest": "workspace:type-fest__4.x@*", "vite": "catalog:" diff --git a/apps/playground/src/components/Editor/EditorPane.tsx b/apps/playground/src/components/Editor/EditorPane.tsx index 8b581c212..6fafbe5fb 100644 --- a/apps/playground/src/components/Editor/EditorPane.tsx +++ b/apps/playground/src/components/Editor/EditorPane.tsx @@ -1,7 +1,6 @@ import { useEffect, useRef, useState } from 'react'; import { useTheme, useTranslation } from '@douglasneuroinformatics/libui/hooks'; -import MonacoEditor from '@monaco-editor/react'; import { useEditorErrorSync } from '@/hooks/useEditorErrorSync'; import { useFilesRef } from '@/hooks/useFilesRef'; @@ -11,6 +10,7 @@ import { useAppStore } from '@/store'; import { getImageMIMEType, inferFileType, isBase64EncodedFileType } from '@/utils/file'; import { EditorPanePlaceholder } from './EditorPanePlaceholder'; +import { MonacoEditor } from './MonacoEditor'; import type { MonacoEditorType, MonacoType } from './types'; @@ -39,8 +39,8 @@ export const EditorPane = () => { Object.keys(libs).forEach((filename) => { const uri = monaco.Uri.parse(filename); if (!monaco.editor.getModel(uri)) { - monaco.languages.typescript.javascriptDefaults.addExtraLib(libs[filename]!, filename); - monaco.languages.typescript.typescriptDefaults.addExtraLib(libs[filename]!, filename); + monaco.typescript.javascriptDefaults.addExtraLib(libs[filename]!, filename); + monaco.typescript.typescriptDefaults.addExtraLib(libs[filename]!, filename); monaco.editor.createModel(libs[filename]!, 'typescript', uri); } }); @@ -78,7 +78,7 @@ export const EditorPane = () => { if (monaco.editor.getModel(uri)) { continue; } else if (fileType === 'typescript') { - monaco.languages.typescript.typescriptDefaults.addExtraLib(file.content, file.name); + monaco.typescript.typescriptDefaults.addExtraLib(file.content, file.name); monaco.editor.createModel(file.content, 'typescript', uri); } else if (fileType === 'javascript') { monaco.editor.createModel(file.content, 'javascript', uri); @@ -131,10 +131,9 @@ export const EditorPane = () => { return ( { path={defaultFile.name} theme={`odc-${theme}`} onChange={(value) => { - setSelectedFileContent(value ?? ''); + setSelectedFileContent(value); }} onMount={handleEditorDidMount} /> diff --git a/apps/playground/src/components/Editor/MonacoEditor.tsx b/apps/playground/src/components/Editor/MonacoEditor.tsx new file mode 100644 index 000000000..93f0361e0 --- /dev/null +++ b/apps/playground/src/components/Editor/MonacoEditor.tsx @@ -0,0 +1,85 @@ +import { useEffect, useRef } from 'react'; + +import * as monaco from 'monaco-editor'; + +import type { MonacoEditorType, MonacoType } from './types'; + +const viewStates = new WeakMap(); + +const saveViewState = (editor: MonacoEditorType) => { + const model = editor.getModel(); + if (model) { + viewStates.set(model, editor.saveViewState()); + } +}; + +const getOrCreateModel = (path: string, defaultValue: string, defaultLanguage: string) => { + const uri = monaco.Uri.parse(path); + return monaco.editor.getModel(uri) ?? monaco.editor.createModel(defaultValue, defaultLanguage, uri); +}; + +export type MonacoEditorProps = { + className?: string; + defaultLanguage: string; + defaultValue: string; + onChange: (value: string) => void; + onMount: (editor: MonacoEditorType, monaco: MonacoType) => void; + options: monaco.editor.IEditorOptions & monaco.editor.IGlobalEditorOptions; + path: string; + theme: string; +}; + +/** + * Shows the model of `path`, creating it from `defaultValue` the first time. Models are never disposed + * here, so a file keeps its content and undo history when the editor switches away or unmounts. + */ +export const MonacoEditor = ({ + className, + defaultLanguage, + defaultValue, + onChange, + onMount, + options, + path, + theme +}: MonacoEditorProps) => { + const containerRef = useRef(null); + const editorRef = useRef(null); + + useEffect(() => { + const editor = monaco.editor.create(containerRef.current!, { ...options, model: null }); + editorRef.current = editor; + return () => { + saveViewState(editor); + editor.dispose(); + }; + }, []); + + useEffect(() => { + const editor = editorRef.current!; + saveViewState(editor); + const model = getOrCreateModel(path, defaultValue, defaultLanguage); + editor.setModel(model); + editor.restoreViewState(viewStates.get(model) ?? null); + }, [path]); + + useEffect(() => { + onMount(editorRef.current!, monaco); + }, []); + + useEffect(() => { + editorRef.current!.updateOptions(options); + }, [options]); + + useEffect(() => { + monaco.editor.setTheme(theme); + }, [theme]); + + useEffect(() => { + const editor = editorRef.current!; + const subscription = editor.onDidChangeModelContent(() => onChange(editor.getValue())); + return () => subscription.dispose(); + }, [onChange]); + + return
; +}; diff --git a/apps/playground/src/components/Editor/__tests__/MonacoEditor.test.tsx b/apps/playground/src/components/Editor/__tests__/MonacoEditor.test.tsx new file mode 100644 index 000000000..c180889cd --- /dev/null +++ b/apps/playground/src/components/Editor/__tests__/MonacoEditor.test.tsx @@ -0,0 +1,161 @@ +// @vitest-environment happy-dom + +import { cleanup, render } from '@testing-library/react'; +import * as monaco from 'monaco-editor'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { MonacoEditor } from '../MonacoEditor'; + +import type { MonacoEditorProps } from '../MonacoEditor'; +import type { MonacoEditorType } from '../types'; + +type FakeModel = { dispose: () => void; language: string; uri: string; value: string }; + +const fakeMonaco = vi.hoisted(() => { + const models = new Map(); + + const createFakeEditor = () => { + let model: FakeModel | null = null; + const contentListeners = new Set<() => void>(); + return { + dispose: vi.fn(), + getModel: () => model, + getValue: () => model!.value, + onDidChangeModelContent: (listener: () => void) => { + contentListeners.add(listener); + return { dispose: () => contentListeners.delete(listener) }; + }, + restoreViewState: vi.fn(), + saveViewState: () => ({ savedFrom: model!.uri }), + setModel: vi.fn((nextModel: FakeModel) => { + model = nextModel; + }), + type: (value: string) => { + model!.value = value; + contentListeners.forEach((listener) => listener()); + }, + updateOptions: vi.fn() + }; + }; + + return { + createFakeEditor, + editor: { + create: vi.fn((_container: HTMLElement, _options: object) => createFakeEditor()), + createModel: vi.fn((value: string, language: string, uri: string): FakeModel => { + const model = { dispose: vi.fn(), language, uri, value }; + models.set(uri, model); + return model; + }), + getModel: (uri: string) => models.get(uri) ?? null, + setTheme: vi.fn() + }, + models, + Uri: { parse: (path: string) => path } + }; +}); + +vi.mock('monaco-editor', () => ({ editor: fakeMonaco.editor, Uri: fakeMonaco.Uri })); + +type FakeEditor = ReturnType; + +const defaultProps: MonacoEditorProps = { + defaultLanguage: 'typescript', + defaultValue: 'export {};', + onChange: vi.fn(), + onMount: vi.fn(), + options: { tabSize: 2 }, + path: 'index.ts', + theme: 'odc-light' +}; + +const renderEditor = (props: Partial = {}) => { + const view = render(); + const editor = fakeMonaco.editor.create.mock.results.at(-1)!.value as FakeEditor; + const rerender = (nextProps: Partial) => { + view.rerender(); + }; + return { editor, rerender, unmount: view.unmount }; +}; + +describe('MonacoEditor', () => { + beforeEach(() => { + fakeMonaco.models.clear(); + vi.clearAllMocks(); + }); + + afterEach(() => { + cleanup(); + }); + + it('should create the model of a new path from the default value, in the default language', () => { + const { editor } = renderEditor(); + expect(fakeMonaco.editor.createModel).toHaveBeenCalledExactlyOnceWith('export {};', 'typescript', 'index.ts'); + expect(editor.getModel()).toBe(fakeMonaco.models.get('index.ts')); + }); + + it('should reuse the model a path already has, so the file keeps its content and undo history', () => { + const existingModel = fakeMonaco.editor.createModel('const x = 1;', 'typescript', 'index.ts'); + fakeMonaco.editor.createModel.mockClear(); + const { editor } = renderEditor(); + expect(fakeMonaco.editor.createModel).not.toHaveBeenCalled(); + expect(editor.getModel()).toBe(existingModel); + }); + + it('should swap the editor to the model of the new path when the path changes', () => { + const { editor, rerender } = renderEditor(); + rerender({ defaultLanguage: 'css', defaultValue: 'body {}', path: 'styles.css' }); + expect(fakeMonaco.editor.create).toHaveBeenCalledOnce(); + expect(editor.getModel()).toMatchObject({ language: 'css', uri: 'styles.css', value: 'body {}' }); + }); + + it('should restore the view state a model had when its file was last shown', () => { + const { editor, rerender } = renderEditor(); + rerender({ path: 'other.ts' }); + rerender({ path: 'index.ts' }); + expect(editor.restoreViewState).toHaveBeenLastCalledWith({ savedFrom: 'index.ts' }); + }); + + it('should never dispose a model, neither on a path change nor on unmount', () => { + const { rerender, unmount } = renderEditor(); + rerender({ path: 'other.ts' }); + unmount(); + fakeMonaco.models.forEach((model) => expect(model.dispose).not.toHaveBeenCalled()); + }); + + it('should create the editor with the options and update it when they change', () => { + const { editor, rerender } = renderEditor(); + expect(fakeMonaco.editor.create).toHaveBeenCalledWith(expect.any(HTMLDivElement), { model: null, tabSize: 2 }); + rerender({ options: { tabSize: 4 } }); + expect(editor.updateOptions).toHaveBeenLastCalledWith({ tabSize: 4 }); + }); + + it('should set the theme, and set it again when it changes', () => { + const { rerender } = renderEditor(); + expect(fakeMonaco.editor.setTheme).toHaveBeenLastCalledWith('odc-light'); + rerender({ theme: 'odc-dark' }); + expect(fakeMonaco.editor.setTheme).toHaveBeenLastCalledWith('odc-dark'); + }); + + it('should call onMount once, with the editor already showing its model', () => { + const onMount = vi.fn((editor: MonacoEditorType) => expect(editor.getModel()).not.toBeNull()); + const { editor, rerender } = renderEditor({ onMount }); + rerender({ options: { tabSize: 4 }, path: 'other.ts' }); + expect(onMount).toHaveBeenCalledExactlyOnceWith(editor, monaco); + }); + + it('should pass the content to the latest onChange on every edit', () => { + const onChange = vi.fn(); + const { editor, rerender } = renderEditor(); + rerender({ onChange }); + editor.type('export const x = 1;'); + expect(onChange).toHaveBeenCalledExactlyOnceWith('export const x = 1;'); + expect(defaultProps.onChange).not.toHaveBeenCalled(); + }); + + it('should dispose the editor on unmount', () => { + const { editor, unmount } = renderEditor(); + unmount(); + expect(editor.dispose).toHaveBeenCalledOnce(); + }); +}); diff --git a/apps/playground/src/components/Editor/setup.ts b/apps/playground/src/components/Editor/setup.ts index 7cd604f0d..e928ca1ec 100644 --- a/apps/playground/src/components/Editor/setup.ts +++ b/apps/playground/src/components/Editor/setup.ts @@ -1,12 +1,11 @@ -import { loader } from '@monaco-editor/react'; import envTypes from '@opendatacapture/runtime-v1/env?raw'; import * as monaco from 'monaco-editor'; -import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'; -import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'; -import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'; -import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'; -import TypeScriptWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'; -import { SuggestAdapter } from 'monaco-editor/esm/vs/language/typescript/tsMode'; +import EditorWorker from 'monaco-editor/editor/editor.worker?worker'; +import CssWorker from 'monaco-editor/languages/features/css/css.worker?worker'; +import HtmlWorker from 'monaco-editor/languages/features/html/html.worker?worker'; +import JsonWorker from 'monaco-editor/languages/features/json/json.worker?worker'; +import TypeScriptWorker from 'monaco-editor/languages/features/typescript/ts.worker?worker'; +import { SuggestAdapter } from 'monaco-editor/languages/features/typescript/tsMode'; import prettierPluginBabel from 'prettier/plugins/babel'; import prettierPluginEstree from 'prettier/plugins/estree'; import prettier from 'prettier/standalone'; @@ -32,125 +31,119 @@ self.MonacoEnvironment = { } }; -loader.config({ monaco }); - -{ - const monaco = await loader.init(); - - const defaults: monaco.languages.typescript.ModeConfiguration = { - codeActions: true, - completionItems: false, - definitions: true, - diagnostics: true, - documentHighlights: true, - documentRangeFormattingEdits: true, - documentSymbols: true, - hovers: true, - inlayHints: true, - onTypeFormattingEdits: true, - references: true, - rename: true, - signatureHelp: true - }; - - monaco.languages.typescript.javascriptDefaults.setModeConfiguration(defaults); - monaco.languages.typescript.typescriptDefaults.setModeConfiguration(defaults); - - // eslint-disable-next-line @typescript-eslint/no-misused-promises - monaco.languages.onLanguage('typescript', async () => { - const worker = await monaco.languages.typescript.getTypeScriptWorker(); - monaco.languages.registerCompletionItemProvider('typescript', new TypeScriptSuggestAdapter(worker)); - }); - - // eslint-disable-next-line @typescript-eslint/no-misused-promises - monaco.languages.onLanguage('javascript', async () => { - const worker = await monaco.languages.typescript.getJavaScriptWorker(); - monaco.languages.registerCompletionItemProvider('javascript', new TypeScriptSuggestAdapter(worker)); - }); - - /** - * Setup the TypeScript compiler options as similarly as possible to - * the project setup. This is limited by an absence of modern options - * (e.g., module resolution) in the monaco enum options. - */ - - const baseTypeScriptOptions: monaco.languages.typescript.CompilerOptions = { - allowJs: true, - allowSyntheticDefaultImports: false, - checkJs: true, - forceConsistentCasingInFileNames: true, - isolatedModules: true, - jsx: monaco.languages.typescript.JsxEmit.ReactJSX, - jsxImportSource: '/runtime/v1/react@19.x', - module: monaco.languages.typescript.ModuleKind.ESNext, - moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs, - newLine: monaco.languages.typescript.NewLineKind.LineFeed, - strict: false, - target: monaco.languages.typescript.ScriptTarget.ES2020 - }; - - monaco.languages.typescript.javascriptDefaults.setCompilerOptions(baseTypeScriptOptions); - monaco.languages.typescript.typescriptDefaults.setCompilerOptions({ - ...baseTypeScriptOptions, - allowImportingTsExtensions: true, - strict: true - }); - - /** - * Define custom light and dark themes for the editor - */ - monaco.editor.defineTheme('odc-light', { - base: 'vs', - colors: { - // slate-50 - 'editor.background': '#F8FAFC' - }, - inherit: true, - rules: [] - }); - - monaco.editor.defineTheme('odc-dark', { - base: 'vs-dark', - colors: { - // slate-800 - 'editor.background': '#1E293B' - }, - inherit: true, - rules: [] - }); - - /** - * Configure the monaco instance to use prettier as the document formatter. - * The keyboard shortcut to format the document is set to Alt + F. - */ - monaco.editor.addKeybindingRule({ - command: 'editor.action.formatDocument', - keybinding: monaco.KeyMod.Alt | monaco.KeyCode.KeyF - }); - - const documentFormattingEditProvider: monaco.languages.DocumentFormattingEditProvider = { - async provideDocumentFormattingEdits(model) { - const range = model.getFullModelRange(); - const value = model.getValue(); - const text = await prettier.format(value, { - parser: 'babel-ts', - plugins: [prettierPluginBabel, prettierPluginEstree], - printWidth: 120, - singleQuote: true, - trailingComma: 'none' - }); - return [{ range, text }]; - } - }; +const defaults: monaco.typescript.ModeConfiguration = { + codeActions: true, + completionItems: false, + definitions: true, + diagnostics: true, + documentHighlights: true, + documentRangeFormattingEdits: true, + documentSymbols: true, + hovers: true, + inlayHints: true, + onTypeFormattingEdits: true, + references: true, + rename: true, + signatureHelp: true +}; + +monaco.typescript.javascriptDefaults.setModeConfiguration(defaults); +monaco.typescript.typescriptDefaults.setModeConfiguration(defaults); + +// eslint-disable-next-line @typescript-eslint/no-misused-promises +monaco.languages.onLanguage('typescript', async () => { + const worker = await monaco.typescript.getTypeScriptWorker(); + monaco.languages.registerCompletionItemProvider('typescript', new TypeScriptSuggestAdapter(worker)); +}); + +// eslint-disable-next-line @typescript-eslint/no-misused-promises +monaco.languages.onLanguage('javascript', async () => { + const worker = await monaco.typescript.getJavaScriptWorker(); + monaco.languages.registerCompletionItemProvider('javascript', new TypeScriptSuggestAdapter(worker)); +}); + +/** + * Setup the TypeScript compiler options as similarly as possible to + * the project setup. This is limited by an absence of modern options + * (e.g., module resolution) in the monaco enum options. + */ + +const baseTypeScriptOptions: monaco.typescript.CompilerOptions = { + allowJs: true, + allowSyntheticDefaultImports: false, + checkJs: true, + forceConsistentCasingInFileNames: true, + isolatedModules: true, + jsx: monaco.typescript.JsxEmit.ReactJSX, + jsxImportSource: '/runtime/v1/react@19.x', + module: monaco.typescript.ModuleKind.ESNext, + moduleResolution: monaco.typescript.ModuleResolutionKind.NodeJs, + newLine: monaco.typescript.NewLineKind.LineFeed, + strict: false, + target: monaco.typescript.ScriptTarget.ES2020 +}; - monaco.languages.registerDocumentFormattingEditProvider('javascript', documentFormattingEditProvider); - monaco.languages.registerDocumentFormattingEditProvider('typescript', documentFormattingEditProvider); +monaco.typescript.javascriptDefaults.setCompilerOptions(baseTypeScriptOptions); +monaco.typescript.typescriptDefaults.setCompilerOptions({ + ...baseTypeScriptOptions, + allowImportingTsExtensions: true, + strict: true +}); + +/** + * Define custom light and dark themes for the editor + */ +monaco.editor.defineTheme('odc-light', { + base: 'vs', + colors: { + // slate-50 + 'editor.background': '#F8FAFC' + }, + inherit: true, + rules: [] +}); + +monaco.editor.defineTheme('odc-dark', { + base: 'vs-dark', + colors: { + // slate-800 + 'editor.background': '#1E293B' + }, + inherit: true, + rules: [] +}); + +/** + * Configure the monaco instance to use prettier as the document formatter. + * The keyboard shortcut to format the document is set to Alt + F. + */ +monaco.editor.addKeybindingRule({ + command: 'editor.action.formatDocument', + keybinding: monaco.KeyMod.Alt | monaco.KeyCode.KeyF +}); + +const documentFormattingEditProvider: monaco.languages.DocumentFormattingEditProvider = { + async provideDocumentFormattingEdits(model) { + const range = model.getFullModelRange(); + const value = model.getValue(); + const text = await prettier.format(value, { + parser: 'babel-ts', + plugins: [prettierPluginBabel, prettierPluginEstree], + printWidth: 120, + singleQuote: true, + trailingComma: 'none' + }); + return [{ range, text }]; + } +}; - // Other - monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true); +monaco.languages.registerDocumentFormattingEditProvider('javascript', documentFormattingEditProvider); +monaco.languages.registerDocumentFormattingEditProvider('typescript', documentFormattingEditProvider); - const uri = monaco.Uri.parse('globals.d.ts'); +// Other +monaco.typescript.typescriptDefaults.setEagerModelSync(true); - monaco.languages.typescript.typescriptDefaults.addExtraLib(envTypes, 'globals.d.ts'); - monaco.editor.createModel(envTypes, 'typescript', uri); -} +const uri = monaco.Uri.parse('globals.d.ts'); + +monaco.typescript.typescriptDefaults.addExtraLib(envTypes, 'globals.d.ts'); +monaco.editor.createModel(envTypes, 'typescript', uri); diff --git a/apps/playground/src/components/MainContent/MainContent.tsx b/apps/playground/src/components/MainContent/MainContent.tsx index 244962df9..25e88283c 100644 --- a/apps/playground/src/components/MainContent/MainContent.tsx +++ b/apps/playground/src/components/MainContent/MainContent.tsx @@ -11,12 +11,13 @@ export const MainContent = () => { return (
{isDesktop ? ( - - + // A Panel's id is also its data-testid, which is the only testid the library lets it carry. + + - + diff --git a/apps/playground/src/components/Resizable/Resizable.stories.tsx b/apps/playground/src/components/Resizable/Resizable.stories.tsx index e478f77a4..b3e7b227c 100644 --- a/apps/playground/src/components/Resizable/Resizable.stories.tsx +++ b/apps/playground/src/components/Resizable/Resizable.stories.tsx @@ -10,21 +10,21 @@ export const Default: Story = { args: { children: ( <> - +
One
- - - + + +
Two
- +
Three
@@ -34,6 +34,6 @@ export const Default: Story = { ), className: 'max-w-md rounded-lg border', - direction: 'horizontal' + orientation: 'horizontal' } }; diff --git a/apps/playground/src/components/Resizable/ResizableHandle.tsx b/apps/playground/src/components/Resizable/ResizableHandle.tsx index ce1847620..24a772cfc 100644 --- a/apps/playground/src/components/Resizable/ResizableHandle.tsx +++ b/apps/playground/src/components/Resizable/ResizableHandle.tsx @@ -1,14 +1,16 @@ import * as React from 'react'; import { cn } from '@douglasneuroinformatics/libui/utils'; -import { PanelResizeHandle } from 'react-resizable-panels'; +import { Separator } from 'react-resizable-panels'; -export type ResizableHandleProps = React.ComponentProps; +export type ResizableHandleProps = React.ComponentProps; +// The separator between stacked panels is a horizontal line, so the library marks the separator of a +// vertical group `aria-orientation="horizontal"`; the stacked-layout styles key on that. export const ResizableHandle = ({ className, ...props }: ResizableHandleProps) => ( - ; +export type ResizablePanelGroupProps = React.ComponentProps; export const ResizablePanelGroup = ({ className, ...props }: ResizablePanelGroupProps) => ( - + ); diff --git a/apps/playground/src/components/Resizable/__tests__/ResizableHandle.test.tsx b/apps/playground/src/components/Resizable/__tests__/ResizableHandle.test.tsx new file mode 100644 index 000000000..66d59a613 --- /dev/null +++ b/apps/playground/src/components/Resizable/__tests__/ResizableHandle.test.tsx @@ -0,0 +1,41 @@ +import { renderToStaticMarkup } from 'react-dom/server'; + +import { Panel } from 'react-resizable-panels'; +import type { Orientation } from 'react-resizable-panels'; +import { describe, expect, it } from 'vitest'; + +import { ResizableHandle } from '../ResizableHandle'; +import { ResizablePanelGroup } from '../ResizablePanelGroup'; + +const renderSeparator = (orientation: Orientation) => { + const markup = renderToStaticMarkup( + + + + + + ); + const tag = /]*role="separator"[^>]*>/.exec(markup)![0]; + const attribute = (name: string) => new RegExp(`${name}="([^"]*)"`).exec(tag)![1]!; + return { ariaOrientation: attribute('aria-orientation'), className: attribute('class') }; +}; + +const styledOrientations = (className: string) => { + return new Set(Array.from(className.matchAll(/aria-\[orientation=(\w+)\]:/g), ([, orientation]) => orientation)); +}; + +describe('ResizableHandle', () => { + it('should apply its stacked-layout styles in a vertical group, keyed on the aria-orientation the library renders there', () => { + const { ariaOrientation, className } = renderSeparator('vertical'); + expect(styledOrientations(className)).toStrictEqual(new Set([ariaOrientation])); + }); + + it('should leave its stacked-layout styles off in a horizontal group, so the handle stays a vertical bar', () => { + const { ariaOrientation, className } = renderSeparator('horizontal'); + expect(styledOrientations(className)).not.toContain(ariaOrientation); + }); + + it('should keep the caller class name, which MainContent uses to set the margin beside the preview', () => { + expect(renderSeparator('horizontal').className.split(' ')).toContain('mr-12'); + }); +}); diff --git a/apps/playground/src/components/Resizable/__tests__/ResizablePanelGroup.test.tsx b/apps/playground/src/components/Resizable/__tests__/ResizablePanelGroup.test.tsx new file mode 100644 index 000000000..57052d0aa --- /dev/null +++ b/apps/playground/src/components/Resizable/__tests__/ResizablePanelGroup.test.tsx @@ -0,0 +1,30 @@ +import { renderToStaticMarkup } from 'react-dom/server'; + +import { Panel } from 'react-resizable-panels'; +import type { Orientation } from 'react-resizable-panels'; +import { describe, expect, it } from 'vitest'; + +import { ResizablePanelGroup } from '../ResizablePanelGroup'; + +const renderGroup = (orientation: Orientation) => { + const markup = renderToStaticMarkup( + + + + ); + return /]*data-group[^>]*>/.exec(markup)![0]; +}; + +describe('ResizablePanelGroup', () => { + it('should stack the panels of a vertical group in a column, which no class of its own does any more', () => { + expect(renderGroup('vertical')).toContain('flex-direction:column'); + }); + + it('should lay the panels of a horizontal group out in a row', () => { + expect(renderGroup('horizontal')).toContain('flex-direction:row'); + }); + + it('should keep the caller class name alongside its own', () => { + expect(renderGroup('horizontal')).toContain('class="flex h-full w-full rounded-lg"'); + }); +}); diff --git a/apps/playground/src/typings/monaco-editor.d.ts b/apps/playground/src/typings/monaco-editor.d.ts index 20df33d3f..f762c5276 100644 --- a/apps/playground/src/typings/monaco-editor.d.ts +++ b/apps/playground/src/typings/monaco-editor.d.ts @@ -1,4 +1,4 @@ -declare module 'monaco-editor/esm/vs/language/typescript/tsMode' { +declare module 'monaco-editor/languages/features/typescript/tsMode' { export class SuggestAdapter { triggerCharacters?: string[]; constructor(worker: any): void; diff --git a/apps/playground/vite.config.ts b/apps/playground/vite.config.ts index 51fd27d75..60c229308 100644 --- a/apps/playground/vite.config.ts +++ b/apps/playground/vite.config.ts @@ -7,7 +7,7 @@ import react from '@vitejs/plugin-react-swc'; import { defineConfig } from 'vite'; import type { Plugin } from 'vite'; -import type { PlaygroundConfig } from './src/preview/config'; +import type { PlaygroundConfig } from './src/preview/config.ts'; // Read straight from the monorepo root rather than through `@opendatacapture/release-info`: that // package pulls in `@opendatacapture/schemas`, which ships raw TypeScript, and loading it here would @@ -32,7 +32,7 @@ export default defineConfig(({ mode }) => ({ build: { chunkSizeWarningLimit: 1000, emptyOutDir: false, - rollupOptions: { + rolldownOptions: { external: ['esbuild'], input: { index: path.resolve(import.meta.dirname, 'index.html'), @@ -47,8 +47,10 @@ export default defineConfig(({ mode }) => ({ __GITHUB_REPO_URL__: `'${process.env.GITHUB_REPO_URL ?? '#'}'` }, optimizeDeps: { - esbuildOptions: { - target: 'es2022' + rolldownOptions: { + transform: { + target: 'es2022' + } }, exclude: ['@swc/wasm-web'], include: ['react/*', 'react-dom/*'] diff --git a/apps/playground/vitest.config.ts b/apps/playground/vitest.config.ts index 9ae298ccb..451529353 100644 --- a/apps/playground/vitest.config.ts +++ b/apps/playground/vitest.config.ts @@ -2,7 +2,7 @@ import * as path from 'node:path'; import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/apps/web/package.json b/apps/web/package.json index c87f65aa3..b93e66093 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -41,14 +41,15 @@ "immer": "^11.1.18", "jwt-decode": "^4.0.0", "lodash-es": "workspace:lodash-es__4.x@*", - "lucide-react": "^0.577.0", + "lucide-react": "^1.49.0", "motion": "catalog:", "msgpackr": "catalog:", "papaparse": "workspace:papaparse__5.x@*", "qrcode": "^1.5.4", "react": "workspace:react__19.x@*", "react-dom": "workspace:react-dom__19.x@*", - "recharts": "^2.15.2", + "react-is": "catalog:react19", + "recharts": "^3.10.1", "ts-pattern": "workspace:ts-pattern__5.x@*", "type-fest": "workspace:type-fest__4.x@*", "xlsx": "^0.18.5", diff --git a/apps/web/src/components/GitHubIcon/GitHubIcon.tsx b/apps/web/src/components/GitHubIcon/GitHubIcon.tsx new file mode 100644 index 000000000..3b72b9363 --- /dev/null +++ b/apps/web/src/components/GitHubIcon/GitHubIcon.tsx @@ -0,0 +1,17 @@ +type GitHubIconProps = { + className?: string; +}; + +// GitHub's official mark: the 16px `mark-github` octicon from @primer/octicons 19.39.0 (MIT). lucide +// 1.0 removed every brand icon, and its old GitHub drawing was a modified logo. +export const GitHubIcon = ({ className }: GitHubIconProps) => ( + +); diff --git a/apps/web/src/components/GitHubIcon/__tests__/GitHubIcon.test.tsx b/apps/web/src/components/GitHubIcon/__tests__/GitHubIcon.test.tsx new file mode 100644 index 000000000..8f78d898a --- /dev/null +++ b/apps/web/src/components/GitHubIcon/__tests__/GitHubIcon.test.tsx @@ -0,0 +1,26 @@ +import { cleanup, render } from '@testing-library/react'; +import { afterEach, describe, expect, it } from 'vitest'; + +import { GitHubIcon } from '../GitHubIcon'; + +const renderMark = (className?: string) => render().container.querySelector('svg')!; + +describe('GitHubIcon', () => { + afterEach(cleanup); + + it('should be hidden from assistive technology, since the link text beside it already names the destination', () => { + expect(renderMark().getAttribute('aria-hidden')).toBe('true'); + }); + + it('should fill with the current text colour, so it matches the link it sits in', () => { + expect(renderMark().getAttribute('fill')).toBe('currentColor'); + }); + + it("should keep the octicon's own 16px viewBox, so the path is not cropped", () => { + expect(renderMark().getAttribute('viewBox')).toBe('0 0 16 16'); + }); + + it('should apply the caller class name, so the call site controls its size', () => { + expect(renderMark('h-4 w-4').getAttribute('class')).toBe('h-4 w-4'); + }); +}); diff --git a/apps/web/src/components/GitHubIcon/index.ts b/apps/web/src/components/GitHubIcon/index.ts new file mode 100644 index 000000000..161713953 --- /dev/null +++ b/apps/web/src/components/GitHubIcon/index.ts @@ -0,0 +1 @@ +export * from './GitHubIcon'; diff --git a/apps/web/src/components/LineGraph/LineGraph.tsx b/apps/web/src/components/LineGraph/LineGraph.tsx index 0fad927a9..56576105f 100644 --- a/apps/web/src/components/LineGraph/LineGraph.tsx +++ b/apps/web/src/components/LineGraph/LineGraph.tsx @@ -15,7 +15,7 @@ import { XAxis, YAxis } from 'recharts'; -import type { LineProps } from 'recharts'; +import type { LegendPayload, LineProps } from 'recharts'; import type { ConditionalKeys } from 'type-fest'; /** An array of arbitrary objects with data to graph */ @@ -69,6 +69,8 @@ function LineGraphComponent({ const { resolvedLanguage } = useTranslation('libui'); const [theme] = useTheme(); + const lineIndex = ({ dataKey }: Pick) => lines.findIndex(({ val }) => val === dataKey); + return ( @@ -99,8 +101,10 @@ function LineGraphComponent({ /> { - const date = new Date(time); + itemSorter={lineIndex} + // recharts types every tooltip label as a ReactNode, but on this number axis it is the x value + labelFormatter={(time) => { + const date = new Date(Number(time)); return new Intl.DateTimeFormat(resolvedLanguage, { dateStyle: 'full', timeStyle: 'medium' @@ -120,7 +124,7 @@ function LineGraphComponent({ {err && } ))} - + ); diff --git a/apps/web/src/components/LineGraph/__tests__/LineGraph.test.tsx b/apps/web/src/components/LineGraph/__tests__/LineGraph.test.tsx index 63ee7b704..c8cba20cf 100644 --- a/apps/web/src/components/LineGraph/__tests__/LineGraph.test.tsx +++ b/apps/web/src/components/LineGraph/__tests__/LineGraph.test.tsx @@ -39,15 +39,14 @@ const renderGraph = ( const lineCurves = (container: HTMLElement) => [...container.querySelectorAll('.recharts-line-curve')]; const xAxisTicks = (container: HTMLElement) => - [...container.querySelectorAll('.recharts-xAxis .recharts-cartesian-axis-tick-value')].map( + [...container.querySelectorAll('.recharts-xAxis-tick-labels .recharts-cartesian-axis-tick-value')].map( (tick) => tick.textContent ); -/** happy-dom's MouseEvent has no pageX/pageY, which recharts reads to find the hovered point. */ -const hover = (container: HTMLElement, { pageX, pageY }: { pageX: number; pageY: number }) => { - const event = new MouseEvent('mousemove', { bubbles: true }); - Object.defineProperties(event, { pageX: { value: pageX }, pageY: { value: pageY } }); - fireEvent(container.querySelector('.recharts-wrapper')!, event); +/** Recharts handles a mouse move on the next animation frame, so wait for one before reading the tooltip. */ +const hover = async (container: HTMLElement, { clientX, clientY }: { clientX: number; clientY: number }) => { + fireEvent.mouseMove(container.querySelector('.recharts-wrapper')!, { clientX, clientY }); + await act(() => new Promise((resolve) => requestAnimationFrame(() => resolve()))); }; describe('LineGraph', () => { @@ -74,14 +73,23 @@ describe('LineGraph', () => { expect(lineCurves(renderGraph([scoreLine], undefined))).toHaveLength(1); }); - it('should label the tooltip with the full date in the interface language', () => { + it('should label the tooltip with the full date in the interface language', async () => { void i18n.changeLanguage('fr'); const container = renderGraph(); - hover(container, { pageX: 420, pageY: 200 }); + await hover(container, { clientX: 420, clientY: 200 }); expect(container.querySelector('.recharts-tooltip-label')?.textContent).toMatch(/^vendredi 2 janvier 2026/); }); - it('should name each line in the legend', () => { + it('should list the hovered values in the tooltip in the order the lines are given, not alphabetically', async () => { + const container = renderGraph([scoreLine, { name: 'Error', val: 'scoreError' }]); + await hover(container, { clientX: 420, clientY: 200 }); + expect([...container.querySelectorAll('.recharts-tooltip-item-name')].map((item) => item.textContent)).toEqual([ + 'Score', + 'Error' + ]); + }); + + it('should name each line in the legend in the order the lines are given, not alphabetically', () => { const container = renderGraph([scoreLine, { name: 'Error', val: 'scoreError' }]); expect([...container.querySelectorAll('.recharts-legend-item-text')].map((item) => item.textContent)).toEqual([ 'Score', diff --git a/apps/web/src/components/LoginBranding/LoginBrandingPanel.tsx b/apps/web/src/components/LoginBranding/LoginBrandingPanel.tsx index 220735b3d..a82a615fb 100644 --- a/apps/web/src/components/LoginBranding/LoginBrandingPanel.tsx +++ b/apps/web/src/components/LoginBranding/LoginBrandingPanel.tsx @@ -12,8 +12,9 @@ import type { PanelSection, ResourceLink } from '@opendatacapture/schemas/setup'; -import { BookOpenIcon, GithubIcon, LinkIcon } from 'lucide-react'; +import { BookOpenIcon, LinkIcon } from 'lucide-react'; +import { GitHubIcon } from '@/components/GitHubIcon'; import { config } from '@/config'; import { getLoginGradient } from '@/utils/branding'; import { getValueForLanguage } from '@/utils/language'; @@ -191,7 +192,7 @@ const PanelFooter = ({ preview, showFooterLinks, tc, tl }: PanelFooterProps) => rel="noopener noreferrer" target="_blank" > - + {tl({ en: 'Source Code', es: 'Código fuente', fr: 'Code source' })} screen.getByTestId('login-branding-panel'); const heading = () => screen.getByRole('heading', { level: 1 }); const logoImage = () => screen.getByRole('img'); const builtInLogo = () => panel().querySelector('svg[viewBox="0 0 320 259"]'); +const sourceCodeMark = () => + screen.getByRole('link', { name: 'Source Code' }).querySelector('svg[viewBox="0 0 16 16"]')!; const sectionTexts = () => [...panel().children[1]!.children].map((section) => section.textContent); describe('LoginBrandingPanel', () => { @@ -340,6 +342,16 @@ describe('LoginBrandingPanel', () => { expect(screen.getByRole('link', { name: 'Documentation' }).getAttribute('href')).toBe('https://docs.example.org'); }); + it('should mark the source code link with the GitHub mark at the footer icon size', () => { + renderPanel(); + expect(sourceCodeMark().getAttribute('class')).toBe('h-4 w-4'); + }); + + it('should shrink the GitHub mark in preview mode, so it scales with the miniature footer', () => { + renderPanel(null, { preview: true }); + expect(sourceCodeMark().getAttribute('class')).toBe('h-3 w-3'); + }); + it('should hide the footer links when they are turned off', () => { renderPanel({ showFooterLinks: false }); expect(screen.queryByRole('link')).toBeNull(); diff --git a/apps/web/src/store/slices/auth.slice.ts b/apps/web/src/store/slices/auth.slice.ts index f71119f2a..f40c21e8d 100644 --- a/apps/web/src/store/slices/auth.slice.ts +++ b/apps/web/src/store/slices/auth.slice.ts @@ -1,4 +1,5 @@ -import { createMongoAbility, PureAbility } from '@casl/ability'; +import { createMongoAbility } from '@casl/ability'; +import type { Ability } from '@casl/ability'; import type { TokenPayload } from '@opendatacapture/schemas/auth'; import type { AppAction, AppSubjectName } from '@opendatacapture/schemas/core'; import { jwtDecode } from 'jwt-decode'; @@ -7,7 +8,7 @@ import type { AuthSlice, SliceCreator } from '../types'; const parseAccessToken = (accessToken: string) => { const { groups, permissions, ...rest } = jwtDecode(accessToken); - const ability = createMongoAbility>(permissions); + const ability = createMongoAbility>(permissions); return { currentGroup: groups[0], currentUser: { diff --git a/apps/web/src/testing/stubs.ts b/apps/web/src/testing/stubs.ts index f118a39de..fa9e36a47 100644 --- a/apps/web/src/testing/stubs.ts +++ b/apps/web/src/testing/stubs.ts @@ -1,11 +1,12 @@ -import { createMongoAbility, PureAbility } from '@casl/ability'; +import { createMongoAbility } from '@casl/ability'; +import type { Ability } from '@casl/ability'; import type { AppAction, AppSubjectName } from '@opendatacapture/schemas/core'; import type { Session } from '@opendatacapture/schemas/session'; import type { CurrentUser } from '@/store/types'; export const currentUser: CurrentUser = Object.freeze({ - ability: createMongoAbility>([{ action: 'manage', subject: 'all' }]), + ability: createMongoAbility>([{ action: 'manage', subject: 'all' }]), firstName: 'Jane', groups: [], id: '123', diff --git a/apps/web/src/utils/__tests__/series-overview.test.ts b/apps/web/src/utils/__tests__/series-overview.test.ts index 099324dbc..b977341a2 100644 --- a/apps/web/src/utils/__tests__/series-overview.test.ts +++ b/apps/web/src/utils/__tests__/series-overview.test.ts @@ -29,4 +29,12 @@ describe('sortSeriesOverviewRows', () => { ]; expect(titles(sortSeriesOverviewRows(rows))).toEqual(['Follow-up', 'Intake']); }); + + it('should order the series every group shares by title', () => { + const rows = [ + { groupName: null, title: 'Intake' }, + { groupName: null, title: 'Follow-up' } + ]; + expect(titles(sortSeriesOverviewRows(rows))).toEqual(['Follow-up', 'Intake']); + }); }); diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index 8ab517d40..63fd1bbc4 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -26,7 +26,7 @@ export default defineConfig(async ({ command }) => { build: { chunkSizeWarningLimit: 1000, emptyOutDir: false, - rollupOptions: { + rolldownOptions: { external: ['esbuild'] }, sourcemap: true, @@ -36,8 +36,10 @@ export default defineConfig(async ({ command }) => { __RELEASE__: JSON.stringify(await getReleaseInfo()) }, optimizeDeps: { - esbuildOptions: { - target: 'es2022' + rolldownOptions: { + transform: { + target: 'es2022' + } }, include: ['react/*', 'react-dom/*'] }, diff --git a/apps/web/vitest.config.ts b/apps/web/vitest.config.ts index f6a0fe91b..e18c732e6 100644 --- a/apps/web/vitest.config.ts +++ b/apps/web/vitest.config.ts @@ -2,7 +2,7 @@ import * as path from 'node:path'; import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/commitlint.config.ts b/commitlint.config.ts index cc32186c4..f91ea34c8 100644 --- a/commitlint.config.ts +++ b/commitlint.config.ts @@ -3,14 +3,14 @@ import fs from 'node:fs'; import path from 'node:path'; -import yaml from 'js-yaml'; +import { load } from 'js-yaml'; const WORKSPACE_NAME_PREFIX = '@opendatacapture/'; const projectRoot = import.meta.dirname; function readWorkspaceGlobs(): string[] { - const workspace: unknown = yaml.load(fs.readFileSync(path.join(projectRoot, 'pnpm-workspace.yaml'), 'utf8')); + const workspace: unknown = load(fs.readFileSync(path.join(projectRoot, 'pnpm-workspace.yaml'), 'utf8')); if (typeof workspace !== 'object' || workspace === null || !('packages' in workspace)) { throw new Error("pnpm-workspace.yaml has no 'packages' field"); } diff --git a/package.json b/package.json index c3f26fe1b..846463300 100644 --- a/package.json +++ b/package.json @@ -36,17 +36,16 @@ "@commitlint/cli": "catalog:", "@commitlint/config-conventional": "catalog:", "@douglasneuroinformatics/eslint-config": "^6.0.0", - "@douglasneuroinformatics/prettier-config": "^0.3.0", + "@douglasneuroinformatics/prettier-config": "^0.4.0", "@douglasneuroinformatics/tsconfig": "^2.0.0", - "@types/js-yaml": "^4.0.9", "@types/node": "24.x", - "@vitest/coverage-v8": "^4.1.11", + "@vitest/coverage-v8": "^5.0.2", "conventional-commits-parser": "catalog:", "env-cmd": "^11.0.0", "eslint": "9.39.x", "expect-type": "^1.4.0", "husky": "^9.1.7", - "js-yaml": "^4.3.2", + "js-yaml": "^5.4.2", "knip": "^6.38.0", "prettier": "^3.9.9", "prettier-plugin-astro": "^0.14.1", @@ -55,7 +54,7 @@ "tsx": "catalog:", "turbo": "^2.11.5", "typescript": "6.0.x", - "vitest": "^4.1.11" + "vitest": "^5.0.2" }, "os": [ "darwin", @@ -70,7 +69,6 @@ "@types/react": "-", "@types/react-dom": "-", "find-my-way@9": "^9.7.0", - "fastify@5": "^5.12.5", "typescript": "6.0.x", "yaml@2": "^2.9.0" }, diff --git a/packages/instrument-bundler/AGENTS.md b/packages/instrument-bundler/AGENTS.md index ad61fdf64..3aaceccfd 100644 --- a/packages/instrument-bundler/AGENTS.md +++ b/packages/instrument-bundler/AGENTS.md @@ -68,7 +68,17 @@ bundle dropped the entire module and every instrument import failed with `pnpm dev`. `src/vendor/__tests__/esbuild.test.ts` bundles the module with tree shaking to guard this. **`src/parse.ts` is vendored** from `parse-imports` (Apache-2.0, adapted to TypeScript and to run in a -browser). Treat it as third-party: fix it upstream-style or not at all. +browser). Treat it as third-party: fix it upstream-style or not at all. The exception is `parse`, the +adapter over `es-module-lexer`'s records, which upstream does not have: an `es-module-lexer` upgrade is +ported there. Its `importTypes` map must classify every import `type` the lexer reports, so a new one +is a compile error rather than an `undefined`. + +**Nothing visibly fails without the top-level `await init()` in `src/parse.ts`.** `es-module-lexer` +falls back to compiling its Wasm synchronously inside the first `parse`, which Node, Chromium and +Firefox all allow for a module this size, so the CLI, the unit tests and the playground keep working +if the line goes. It stays because the library requires `init()` before `parse` on a browser main +thread, where its README says synchronous compilation is restricted and where it would block the page. +`src/__tests__/parse.test.ts` checks that `init` resolves before the first `parse`. ## Module resolution diff --git a/packages/instrument-bundler/package.json b/packages/instrument-bundler/package.json index de6096d3f..f3ee860e1 100644 --- a/packages/instrument-bundler/package.json +++ b/packages/instrument-bundler/package.json @@ -35,7 +35,7 @@ "dependencies": { "@opendatacapture/runtime-internal": "workspace:*", "commander": "catalog:", - "es-module-lexer": "^2.3.2", + "es-module-lexer": "^3.0.2", "esbuild": "catalog:", "esbuild-wasm": "catalog:", "glob": "^13.0.6", diff --git a/packages/instrument-bundler/src/__tests__/parse.test.ts b/packages/instrument-bundler/src/__tests__/parse.test.ts index 81aeda60f..8a40d2e2d 100644 --- a/packages/instrument-bundler/src/__tests__/parse.test.ts +++ b/packages/instrument-bundler/src/__tests__/parse.test.ts @@ -1,8 +1,25 @@ -import { describe, expect, it, test } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { InstrumentBundlerError } from '../error.js'; import { parse, parseImports, parseModuleSpecifier } from '../parse.js'; +const lexerCalls = vi.hoisted(() => [] as ('init' | 'parse')[]); + +vi.mock('es-module-lexer', async (importOriginal) => { + const lexer = await importOriginal(); + return { + ...lexer, + init: async () => { + await lexer.init(); + lexerCalls.push('init'); + }, + parse: (source: string) => { + lexerCalls.push('parse'); + return lexer.parse(source); + } + }; +}); + const code = ` import React, { useState } from 'react'; import { App } from './App.tsx'; @@ -14,27 +31,47 @@ export const foo = null; export default foo; `; -test('parse', () => { - const result = parse(code); - expect(result).toMatchObject({ - exports: [{ exportName: 'foo' }, { exportName: 'default' }], - imports: [ - { - importPath: 'react', - importType: 'Static', - statement: "import React, { useState } from 'react'" - }, - { - importPath: './App.tsx', - importType: 'Static', - statement: "import { App } from './App.tsx'" - }, - { - importPath: '/hello.js', - importType: 'Dynamic', - statement: "import('/hello.js')" - } - ] +describe('parse', () => { + it('should finish compiling the lexer before it first parses, so parse never compiles it synchronously on a browser main thread', () => { + parse(code); + expect(lexerCalls.slice(0, 2)).toEqual(['init', 'parse']); + }); + + it('should report the path, type and statement of each import and the name of each export', () => { + expect(parse(code)).toMatchObject({ + exports: [{ exportName: 'foo' }, { exportName: 'default' }], + imports: [ + { + importPath: 'react', + importType: 'Static', + statement: "import React, { useState } from 'react'" + }, + { + importPath: './App.tsx', + importType: 'Static', + statement: "import { App } from './App.tsx'" + }, + { + importPath: '/hello.js', + importType: 'Dynamic', + statement: "import('/hello.js')" + } + ] + }); + }); + + it('should classify import.meta as ImportMeta, so parseImports can tell it apart from an import', () => { + expect(parse(`const url = import.meta.url;`).imports).toMatchObject([{ importType: 'ImportMeta' }]); + }); + + it('should classify the module request of a star re-export as a static import', () => { + expect(parse(`export * from './core.js';`).imports).toMatchObject([ + { importPath: './core.js', importType: 'Static', statement: `export * from './core.js'` } + ]); + }); + + it('should leave a star re-export out of the exports, since it exports no name of its own', () => { + expect(parse(`export * from './core.js';`).exports).toEqual([]); }); }); diff --git a/packages/instrument-bundler/src/parse.ts b/packages/instrument-bundler/src/parse.ts index 36a7e94dd..75179b15f 100644 --- a/packages/instrument-bundler/src/parse.ts +++ b/packages/instrument-bundler/src/parse.ts @@ -19,12 +19,13 @@ * limitations under the License. */ -import { parse as _parse, ImportType, init } from 'es-module-lexer'; +import { parse as _parse, init } from 'es-module-lexer'; +import type { Import as LexedImport } from 'es-module-lexer'; import { removeSlashes } from 'slashes'; import { InstrumentBundlerError } from './error.js'; -await init; +await init(); /** * A type representing what kind of module a specifier refers to. @@ -284,19 +285,26 @@ export function parseModuleSpecifier(moduleSpecifierString: string, { isDynamicI } as const; } +// es-module-lexer 2 reported the module request of `export * from` as a static import +const importTypes = { + dynamic: 'Dynamic', + 'import-meta': 'ImportMeta', + 'reexport-star': 'Static', + static: 'Static' +} as const satisfies { [TLexedType in LexedImport['type']]: 'Dynamic' | 'ImportMeta' | 'Static' }; + export function parse(code: string) { const [imports, exports] = _parse(code); return { - exports: exports.map(({ n }) => ({ exportName: n })), - imports: imports.map(({ d, e, n, s, se, ss, t }) => ({ - dynamicImportStartIndex: d, - importPath: n, - importType: ImportType[t], - moduleSpecifierEndIndexExclusive: e, - moduleSpecifierStartIndex: s, - statement: code.slice(ss, se), - statementEndIndex: se, - statementStartIndex: ss + exports: exports.filter((record) => record.type !== 'reexport-all').map(({ name }) => ({ exportName: name })), + imports: imports.map(({ end, importEnd, importStart, specifier, start, type }) => ({ + importPath: specifier, + importType: importTypes[type], + moduleSpecifierEndIndexExclusive: end, + moduleSpecifierStartIndex: start, + statement: code.slice(importStart, importEnd), + statementEndIndex: importEnd, + statementStartIndex: importStart })) }; } @@ -308,18 +316,18 @@ export function parseImports(code: string): Iterable { *[Symbol.iterator]() { for (let { // eslint-disable-next-line prefer-const - dynamicImportStartIndex, + importType, moduleSpecifierEndIndexExclusive, moduleSpecifierStartIndex, // eslint-disable-next-line prefer-const statementStartIndex } of imports) { - const isImportMeta = dynamicImportStartIndex === -2; + const isImportMeta = importType === 'ImportMeta'; if (isImportMeta) { continue; } - const isDynamicImport = dynamicImportStartIndex > -1; + const isDynamicImport = importType === 'Dynamic'; // Include string literal quotes in character range if (!isDynamicImport) { diff --git a/packages/instrument-bundler/vitest.config.ts b/packages/instrument-bundler/vitest.config.ts index 841b15c56..a1d88f895 100644 --- a/packages/instrument-bundler/vitest.config.ts +++ b/packages/instrument-bundler/vitest.config.ts @@ -1,6 +1,6 @@ import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/packages/instrument-interpreter/vitest.config.ts b/packages/instrument-interpreter/vitest.config.ts index a9b387b5b..c0f8611dc 100644 --- a/packages/instrument-interpreter/vitest.config.ts +++ b/packages/instrument-interpreter/vitest.config.ts @@ -1,6 +1,6 @@ import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/packages/instrument-library/AGENTS.md b/packages/instrument-library/AGENTS.md index 17edbf92b..201e8aba9 100644 --- a/packages/instrument-library/AGENTS.md +++ b/packages/instrument-library/AGENTS.md @@ -84,7 +84,8 @@ grouped by kind; `--title` prints a flat list. **It reads `dist`, not `src`, so `packages/runtime-core/src` and every other `/runtime/v1/@[/]` to the `vendor/@/src/` wrapper it is built from — `tsconfig.json`'s `paths` to `runtime/v1/dist` applies only to `tsc`. A runtime import of a new vendored library resolves the - same way once its `vendor/` wrapper exists. + same way once its `vendor/` wrapper exists. That source needs runtime-core's `lowerDecorators` + plugin, which the config imports from `../runtime-core/vitest.config`. - `content.render(done)` of an interactive task mounts into `document.body`; JSX (a form `block`'s `render`) is rendered with `@testing-library/react`, a devDependency. CSS imports load as empty modules. diff --git a/packages/instrument-library/vitest.config.ts b/packages/instrument-library/vitest.config.ts index 9ef25a994..010b4e550 100644 --- a/packages/instrument-library/vitest.config.ts +++ b/packages/instrument-library/vitest.config.ts @@ -2,7 +2,8 @@ import path from 'node:path'; import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; +import { lowerDecorators } from '../runtime-core/vitest.config'; const repositoryRoot = path.resolve(import.meta.dirname, '../..'); @@ -14,6 +15,7 @@ const PACKAGE_SPECIFIER = String.raw`((?:@[^/]+/)?[^/@]+@[^/]+)`; export default mergeConfig( baseConfig, defineProject({ + plugins: [lowerDecorators], resolve: { alias: [ { diff --git a/packages/instrument-stubs/vitest.config.ts b/packages/instrument-stubs/vitest.config.ts index a23e1ed06..25e8e19a3 100644 --- a/packages/instrument-stubs/vitest.config.ts +++ b/packages/instrument-stubs/vitest.config.ts @@ -1,6 +1,6 @@ import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/packages/instrument-utils/vitest.config.ts b/packages/instrument-utils/vitest.config.ts index 9f8df1976..968453077 100644 --- a/packages/instrument-utils/vitest.config.ts +++ b/packages/instrument-utils/vitest.config.ts @@ -1,6 +1,6 @@ import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/packages/playground-url/vitest.config.ts b/packages/playground-url/vitest.config.ts index 3e8757e15..7af8a0bbc 100644 --- a/packages/playground-url/vitest.config.ts +++ b/packages/playground-url/vitest.config.ts @@ -1,6 +1,6 @@ import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/packages/react-core/package.json b/packages/react-core/package.json index 7945830dd..037cfe73e 100644 --- a/packages/react-core/package.json +++ b/packages/react-core/package.json @@ -33,7 +33,7 @@ "@opendatacapture/subject-utils": "workspace:*", "http-status-codes": "^2.3.0", "lodash-es": "workspace:lodash-es__4.x@*", - "lucide-react": "^0.577.0", + "lucide-react": "^1.49.0", "motion": "catalog:", "react-dropzone": "catalog:", "serialize-error": "catalog:", diff --git a/packages/react-core/vitest.config.ts b/packages/react-core/vitest.config.ts index 61d46619c..1b74e5816 100644 --- a/packages/react-core/vitest.config.ts +++ b/packages/react-core/vitest.config.ts @@ -1,6 +1,6 @@ import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/packages/release-info/vitest.config.ts b/packages/release-info/vitest.config.ts index 7791d9975..c074e4c0c 100644 --- a/packages/release-info/vitest.config.ts +++ b/packages/release-info/vitest.config.ts @@ -1,6 +1,6 @@ import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/packages/runtime-bundler/vitest.config.ts b/packages/runtime-bundler/vitest.config.ts index 7b4803403..dd0dd516c 100644 --- a/packages/runtime-bundler/vitest.config.ts +++ b/packages/runtime-bundler/vitest.config.ts @@ -1,6 +1,6 @@ import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/packages/runtime-core/AGENTS.md b/packages/runtime-core/AGENTS.md index a93b4b450..e06a271df 100644 --- a/packages/runtime-core/AGENTS.md +++ b/packages/runtime-core/AGENTS.md @@ -90,7 +90,10 @@ Two tiers, run by different tools. needed; relative imports carry `.js` like the rest of `src/` (Node16 resolution). `i18n.ts` picks `SynchronizedTranslator` or `StandaloneTranslator` from `window` **at import time**, so a test of a browser branch needs a `// @vitest-environment happy-dom` docblock, and one that varies `window` - needs `vi.resetModules()` and a dynamic `import('../i18n.js')`. + needs `vi.resetModules()` and a dynamic `import('../i18n.js')`. `vitest.config.ts` exports + `lowerDecorators`, which runs esbuild over source with decorators before Vite's Oxc transform: Oxc + cannot lower the TC39 decorators in `i18n.ts`, and Node cannot run them. Any project that runs + runtime-core source needs it in its `plugins`, as `packages/instrument-library` has. - **Types: `src/__tests__/define.test-d.ts` and `src/types/__tests__/instrument.form.test-d.ts`**, written with `expectTypeOf` from `expect-type` (a root devDependency). vitest does not collect them; the `tsc --noEmit` half of `pnpm --filter @opendatacapture/runtime-core lint` checks them, diff --git a/packages/runtime-core/vitest.config.ts b/packages/runtime-core/vitest.config.ts index 2d4e245f8..6c1ce625a 100644 --- a/packages/runtime-core/vitest.config.ts +++ b/packages/runtime-core/vitest.config.ts @@ -1,10 +1,35 @@ +import * as path from 'node:path'; + +import { transform } from 'esbuild'; import { defineProject, mergeConfig } from 'vitest/config'; +import type { Plugin } from 'vitest/config'; + +import { baseConfig } from '../../vitest.config.js'; + +const sourceRoot = path.join(import.meta.dirname, 'src') + path.sep; -import baseConfig from '../../vitest.config.js'; +const decoratorPattern = /^\s*@[A-Za-z_$]/m; + +/** + * Oxc, which transforms TypeScript under Vite 8, cannot lower TC39 decorators, and Node cannot run + * them. esbuild, which builds `dist`, lowers them first in every project that runs this source. + */ +export const lowerDecorators: Plugin = { + enforce: 'pre', + name: 'lower-decorators', + async transform(code, id) { + if (!id.startsWith(sourceRoot) || !decoratorPattern.test(code)) { + return null; + } + const result = await transform(code, { loader: 'ts', sourcefile: id, sourcemap: true, target: 'es2022' }); + return { code: result.code, map: result.map }; + } +}; export default mergeConfig( baseConfig, defineProject({ + plugins: [lowerDecorators], test: { name: 'runtime-core', root: import.meta.dirname diff --git a/packages/runtime-internal/vitest.config.ts b/packages/runtime-internal/vitest.config.ts index fe1a086b5..a88a8326e 100644 --- a/packages/runtime-internal/vitest.config.ts +++ b/packages/runtime-internal/vitest.config.ts @@ -1,6 +1,6 @@ import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/packages/runtime-meta/vitest.config.ts b/packages/runtime-meta/vitest.config.ts index b3f5ca561..8e5ea9019 100644 --- a/packages/runtime-meta/vitest.config.ts +++ b/packages/runtime-meta/vitest.config.ts @@ -1,6 +1,6 @@ import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/packages/schemas/src/core/core.ts b/packages/schemas/src/core/core.ts index dec806e8a..c2831a50b 100644 --- a/packages/schemas/src/core/core.ts +++ b/packages/schemas/src/core/core.ts @@ -1,4 +1,4 @@ -import type { PureAbility, RawRuleOf } from '@casl/ability'; +import type { Ability, RawRuleOf } from '@casl/ability'; import { licenses } from '@opendatacapture/licenses'; import type { LicenseIdentifier } from '@opendatacapture/licenses'; import type { Language as InstrumentAuthoringLanguage, Json, JsonLiteral } from '@opendatacapture/runtime-core'; @@ -38,7 +38,7 @@ export const $GroupScopableSubjectName = $AppSubjectName.exclude(['all', 'Instru export const isGroupScopableSubject = (subject: AppSubjectName): subject is GroupScopableSubjectName => $GroupScopableSubjectName.safeParse(subject).success; -export type BaseAppAbility = PureAbility<[AppAction, AppSubjectName]>; +export type BaseAppAbility = Ability<[AppAction, AppSubjectName]>; export type UserPermission = z.infer; export const $UserPermission = z diff --git a/packages/schemas/vitest.config.ts b/packages/schemas/vitest.config.ts index 609fada7d..c468480e8 100644 --- a/packages/schemas/vitest.config.ts +++ b/packages/schemas/vitest.config.ts @@ -1,6 +1,6 @@ import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/packages/serve-instrument/src/__tests__/client.test.tsx b/packages/serve-instrument/src/__tests__/client.test.tsx index c6075228c..4485c838d 100644 --- a/packages/serve-instrument/src/__tests__/client.test.tsx +++ b/packages/serve-instrument/src/__tests__/client.test.tsx @@ -17,19 +17,22 @@ vi.mock('react-dom/client', () => ({ hydrateRoot })); const ROOT_PROPS: RootProps = { instruments: [{ name: 'happiness', type: 'forms' }], page: 'index' }; describe('client', () => { + let hydrateRootArgs: Parameters | undefined; + beforeAll(async () => { document.body.innerHTML = '
'; vi.stubGlobal('__ROOT_PROPS__', ROOT_PROPS); await import('../client'); vi.unstubAllGlobals(); + hydrateRootArgs = hydrateRoot.mock.lastCall; }); it('should hydrate the server-rendered #root element, so the SSR markup is reused rather than replaced', () => { - expect(hydrateRoot.mock.lastCall?.[0]).toBe(document.getElementById('root')); + expect(hydrateRootArgs?.[0]).toBe(document.getElementById('root')); }); it('should hydrate Root in strict mode with the server-injected props, so the client tree matches the SSR markup', () => { - expect(hydrateRoot.mock.lastCall?.[1]).toMatchObject({ + expect(hydrateRootArgs?.[1]).toMatchObject({ props: { children: { props: ROOT_PROPS, type: Root } }, type: StrictMode }); diff --git a/packages/serve-instrument/vitest.config.ts b/packages/serve-instrument/vitest.config.ts index 5384005df..090f93b81 100644 --- a/packages/serve-instrument/vitest.config.ts +++ b/packages/serve-instrument/vitest.config.ts @@ -1,6 +1,6 @@ import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/packages/subject-utils/vitest.config.ts b/packages/subject-utils/vitest.config.ts index 1ae50285f..9a5dcb079 100644 --- a/packages/subject-utils/vitest.config.ts +++ b/packages/subject-utils/vitest.config.ts @@ -1,6 +1,6 @@ import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/packages/vite-plugin-runtime/vitest.config.ts b/packages/vite-plugin-runtime/vitest.config.ts index dde258cb1..1324f13fd 100644 --- a/packages/vite-plugin-runtime/vitest.config.ts +++ b/packages/vite-plugin-runtime/vitest.config.ts @@ -1,6 +1,6 @@ import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 426e3addc..64ae349c8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,8 +7,8 @@ settings: catalogs: default: '@casl/ability': - specifier: ^6.7.1 - version: 6.8.1 + specifier: ^7.0.1 + version: 7.0.1 '@commitlint/cli': specifier: ^21.2.3 version: 21.2.3 @@ -43,14 +43,14 @@ catalogs: specifier: ^6.9.0 version: 6.19.3 '@storybook/addon-docs': - specifier: 10.5.6 - version: 10.5.6 + specifier: ^10.6.1 + version: 10.6.1 '@storybook/addon-themes': - specifier: 10.5.6 - version: 10.5.6 + specifier: ^10.6.1 + version: 10.6.1 '@storybook/react-vite': - specifier: 10.5.6 - version: 10.5.6 + specifier: ^10.6.1 + version: 10.6.1 '@tailwindcss/postcss': specifier: 4.3.3 version: 4.3.3 @@ -103,8 +103,8 @@ catalogs: specifier: ^13.0.1 version: 13.0.1 storybook: - specifier: 10.5.6 - version: 10.5.6 + specifier: ^10.6.1 + version: 10.6.1 tailwindcss: specifier: 4.3.3 version: 4.3.3 @@ -112,8 +112,8 @@ catalogs: specifier: 4.23.15 version: 4.23.15 vite: - specifier: ^7.3.6 - version: 7.3.6 + specifier: ^8.3.1 + version: 8.3.1 zustand: specifier: ^5.0.15 version: 5.0.15 @@ -124,12 +124,14 @@ catalogs: react-dom: specifier: 19.1.0 version: 19.1.0 + react-is: + specifier: 19.1.0 + version: 19.1.0 overrides: '@types/react': '-' '@types/react-dom': '-' find-my-way@9: ^9.7.0 - fastify@5: ^5.12.5 typescript: 6.0.x yaml@2: ^2.9.0 @@ -147,20 +149,17 @@ importers: specifier: ^6.0.0 version: 6.0.0(@typescript-eslint/parser@8.60.1(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3) '@douglasneuroinformatics/prettier-config': - specifier: ^0.3.0 - version: 0.3.0(husky@9.1.7)(prettier-plugin-astro@0.14.1)(prettier-plugin-tailwindcss@0.8.1(prettier-plugin-astro@0.14.1)(prettier@3.9.9))(prettier@3.9.9) + specifier: ^0.4.0 + version: 0.4.0(husky@9.1.7)(prettier-plugin-astro@0.14.1)(prettier-plugin-tailwindcss@0.8.1(prettier-plugin-astro@0.14.1)(prettier@3.9.9))(prettier@3.9.9) '@douglasneuroinformatics/tsconfig': specifier: ^2.0.0 version: 2.0.0(typescript@6.0.3) - '@types/js-yaml': - specifier: ^4.0.9 - version: 4.0.9 '@types/node': specifier: 24.x version: 24.19.0 '@vitest/coverage-v8': - specifier: ^4.1.11 - version: 4.1.11(@vitest/browser@4.1.11)(vitest@4.1.11) + specifier: ^5.0.2 + version: 5.0.2(vitest@5.0.2) conventional-commits-parser: specifier: 'catalog:' version: 7.1.2 @@ -177,8 +176,8 @@ importers: specifier: ^9.1.7 version: 9.1.7 js-yaml: - specifier: ^4.3.2 - version: 4.3.2 + specifier: ^5.4.2 + version: 5.4.2 knip: specifier: ^6.38.0 version: 6.38.0 @@ -204,8 +203,8 @@ importers: specifier: 6.0.x version: 6.0.3 vitest: - specifier: ^4.1.11 - version: 4.1.11(@types/node@24.19.0)(@vitest/coverage-v8@4.1.11)(happy-dom@20.11.15)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + specifier: ^5.0.2 + version: 5.0.2(@types/node@24.19.0)(@vitest/coverage-v8@5.0.2)(happy-dom@20.11.15)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) apps/api: dependencies: @@ -216,11 +215,11 @@ importers: specifier: ^3.1141.0 version: 3.1141.0 '@casl/ability': - specifier: ^6.7.5 - version: 6.8.1 + specifier: 'catalog:' + version: 7.0.1 '@casl/prisma': - specifier: ^1.5.1 - version: 1.6.2(@casl/ability@6.8.1)(@prisma/client@6.19.3(prisma@6.19.3(typescript@6.0.3))(typescript@6.0.3)) + specifier: ^2.0.2 + version: 2.0.2(@casl/ability@7.0.1)(@prisma/client@6.19.3(prisma@6.19.3(typescript@6.0.3))(typescript@6.0.3)) '@douglasneuroinformatics/libcrypto': specifier: 'catalog:' version: 0.0.6 @@ -228,8 +227,8 @@ importers: specifier: 'catalog:' version: 3.2.1(neverthrow@8.2.0)(zod@vendor+zod@3.x) '@douglasneuroinformatics/libnest': - specifier: ^9.0.0 - version: 9.0.0(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6)(@nestjs/platform-fastify@11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6))(@nestjs/testing@11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6)(@nestjs/platform-express@11.2.6))(@prisma/client@6.19.3(prisma@6.19.3(typescript@6.0.3))(typescript@6.0.3))(@swc/types@0.1.28)(fastify@5.12.5)(neverthrow@8.2.0)(reflect-metadata@0.1.14)(rollup@4.61.1)(rxjs@7.8.2)(typescript@6.0.3)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0))(vitest@4.1.11)(zod@vendor+zod@3.x) + specifier: ^10.0.0 + version: 10.0.0(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-fastify@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2)))(@nestjs/testing@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2)))(@prisma/client@6.19.3(prisma@6.19.3(typescript@6.0.3))(typescript@6.0.3))(@swc/types@0.1.28)(fastify@5.12.5)(neverthrow@8.2.0)(reflect-metadata@0.2.2)(rollup@4.61.1)(rxjs@7.8.2)(typescript@6.0.3)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0))(vitest@5.0.2)(zod@vendor+zod@3.x) '@douglasneuroinformatics/libpasswd': specifier: 'catalog:' version: 0.0.3(typescript@6.0.3) @@ -237,32 +236,29 @@ importers: specifier: 'catalog:' version: 0.2.1 '@faker-js/faker': - specifier: ~10.2.0 - version: 10.2.0 + specifier: ^10.6.0 + version: 10.6.0 '@nestjs/axios': specifier: ^12.0.1 - version: 12.0.1(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(axios@1.20.0)(rxjs@7.8.2) + version: 12.0.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.20.0)(rxjs@7.8.2) '@nestjs/common': - specifier: ^11.2.6 - version: 11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2) + specifier: ^12.1.1 + version: 12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/core': - specifier: ^11.2.6 - version: 11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/platform-express@11.2.6)(reflect-metadata@0.1.14)(rxjs@7.8.2) + specifier: ^12.1.1 + version: 12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/jwt': specifier: ^12.0.2 - version: 12.0.2(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2)) + version: 12.0.2(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2)) '@nestjs/passport': specifier: ^12.0.0 - version: 12.0.0(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(passport@0.7.0) - '@nestjs/platform-express': - specifier: ^11.2.6 - version: 11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6) + version: 12.0.0(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) '@nestjs/platform-fastify': - specifier: ^11.2.6 - version: 11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6) + specifier: ^12.1.1 + version: 12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2)) '@nestjs/throttler': specifier: ^6.7.1 - version: 6.7.1(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6)(reflect-metadata@0.1.14) + version: 6.7.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2) '@opendatacapture/demo': specifier: workspace:* version: link:../../packages/demo @@ -327,8 +323,8 @@ importers: specifier: ^4.0.1 version: 4.0.1 reflect-metadata: - specifier: ^0.1.14 - version: 0.1.14 + specifier: ^0.2.2 + version: 0.2.2 rxjs: specifier: ^7.8.2 version: 7.8.2 @@ -340,8 +336,8 @@ importers: version: link:../../vendor/zod@3.x devDependencies: '@nestjs/testing': - specifier: ^11.2.6 - version: 11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6)(@nestjs/platform-express@11.2.6) + specifier: ^12.1.1 + version: 12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2)) '@types/express': specifier: ^5.0.0 version: 5.0.6 @@ -364,8 +360,8 @@ importers: apps/gateway: dependencies: '@cap.js/server': - specifier: ^2.0.0 - version: 2.0.0 + specifier: ^4.0.5 + version: 4.0.5 '@cap.js/widget': specifier: ^0.1.58 version: 0.1.58 @@ -426,7 +422,7 @@ importers: version: link:../../packages/vite-plugin-runtime '@tailwindcss/vite': specifier: 'catalog:' - version: 4.3.3(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + version: 4.3.3(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) '@testing-library/dom': specifier: 'catalog:' version: 10.4.2 @@ -441,7 +437,7 @@ importers: version: 5.0.6 '@vitejs/plugin-react-swc': specifier: ^4.3.3 - version: 4.3.3(@swc/helpers@0.5.23)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + version: 4.3.3(@swc/helpers@0.5.23)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) esbuild: specifier: 'catalog:' version: 0.28.2 @@ -462,7 +458,7 @@ importers: version: link:../../vendor/type-fest@4.x vite: specifier: 'catalog:' - version: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + version: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) apps/outreach: dependencies: @@ -505,10 +501,10 @@ importers: version: 3.7.4 '@astrojs/starlight': specifier: ^0.34.3 - version: 0.34.8(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0)) + version: 0.34.8(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0)) '@astrojs/starlight-tailwind': specifier: 4.0.2 - version: 4.0.2(@astrojs/starlight@0.34.8(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0)))(tailwindcss@4.3.3) + version: 4.0.2(@astrojs/starlight@0.34.8(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0)))(tailwindcss@4.3.3) '@opendatacapture/runtime-core': specifier: workspace:* version: link:../../packages/runtime-core @@ -520,10 +516,10 @@ importers: version: 0.5.20(tailwindcss@4.3.3) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.3.3(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + version: 4.3.3(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) astro: specifier: ^5.15.9 - version: 5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0) + version: 5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0) github-slugger: specifier: ^2.0.0 version: 2.0.0 @@ -534,11 +530,11 @@ importers: specifier: 'catalog:' version: 4.3.3 typedoc: - specifier: 0.27.x - version: 0.27.9(typescript@6.0.3) + specifier: ^0.28.20 + version: 0.28.20(typescript@6.0.3) typedoc-plugin-markdown: - specifier: 4.4.x - version: 4.4.2(typedoc@0.27.9(typescript@6.0.3)) + specifier: ^4.13.1 + version: 4.13.1(typedoc@0.28.20(typescript@6.0.3)) apps/playground: dependencies: @@ -551,9 +547,6 @@ importers: '@douglasneuroinformatics/libui': specifier: 'catalog:' version: 6.16.1(immer@11.1.18)(neverthrow@8.2.0)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)(tailwindcss@4.3.3)(use-sync-external-store@1.6.0(react@vendor+react@19.x))(zod@vendor+zod@3.x) - '@monaco-editor/react': - specifier: ^4.7.0 - version: 4.7.0(monaco-editor@0.54.0)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) '@opendatacapture/instrument-bundler': specifier: workspace:* version: link:../../packages/instrument-bundler @@ -597,11 +590,11 @@ importers: specifier: workspace:lodash-es__4.x@* version: link:../../vendor/lodash-es@4.x lucide-react: - specifier: ^0.577.0 - version: 0.577.0(react@vendor+react@19.x) + specifier: ^1.49.0 + version: 1.49.0(react@vendor+react@19.x) monaco-editor: - specifier: ^0.54.0 - version: 0.54.0 + specifier: ^0.57.0 + version: 0.57.0 motion: specifier: 'catalog:' version: 13.4.4(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) @@ -621,8 +614,8 @@ importers: specifier: ^6.1.6 version: 6.1.6(react@vendor+react@19.x) react-resizable-panels: - specifier: ^3.0.6 - version: 3.0.6(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) + specifier: ^4.14.1 + version: 4.14.1(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) ts-pattern: specifier: workspace:ts-pattern__5.x@* version: link:../../vendor/ts-pattern@5.x @@ -638,13 +631,22 @@ importers: version: link:../../packages/vite-plugin-runtime '@storybook/react-vite': specifier: 'catalog:' - version: 10.5.6(esbuild@0.28.2)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)(rollup@4.61.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(typescript@6.0.3)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + version: 10.6.1(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)(rollup@4.61.1)(storybook@10.6.1(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(typescript@6.0.3)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.3.3(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + version: 4.3.3(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) + '@testing-library/dom': + specifier: 'catalog:' + version: 10.4.2 + '@testing-library/react': + specifier: 'catalog:' + version: 16.3.3(@testing-library/dom@10.4.2)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) '@vitejs/plugin-react-swc': specifier: ^4.3.3 - version: 4.3.3(@swc/helpers@0.5.23)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + version: 4.3.3(@swc/helpers@0.5.23)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) + happy-dom: + specifier: 'catalog:' + version: 20.11.15 tailwindcss: specifier: 'catalog:' version: 4.3.3 @@ -653,13 +655,13 @@ importers: version: link:../../vendor/type-fest@4.x vite: specifier: 'catalog:' - version: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + version: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) apps/web: dependencies: '@casl/ability': specifier: 'catalog:' - version: 6.8.1 + version: 7.0.1 '@douglasneuroinformatics/libjs': specifier: 'catalog:' version: 3.2.1(neverthrow@8.2.0)(zod@vendor+zod@3.x) @@ -736,8 +738,8 @@ importers: specifier: workspace:lodash-es__4.x@* version: link:../../vendor/lodash-es@4.x lucide-react: - specifier: ^0.577.0 - version: 0.577.0(react@vendor+react@19.x) + specifier: ^1.49.0 + version: 1.49.0(react@vendor+react@19.x) motion: specifier: 'catalog:' version: 13.4.4(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) @@ -756,9 +758,12 @@ importers: react-dom: specifier: workspace:react-dom__19.x@* version: link:../../vendor/react-dom@19.x + react-is: + specifier: catalog:react19 + version: 19.1.0 recharts: - specifier: ^2.15.2 - version: 2.15.4(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) + specifier: ^3.10.1 + version: 3.10.1(react-dom@vendor+react-dom@19.x)(react-is@19.1.0)(react@vendor+react@19.x)(redux@5.0.1) ts-pattern: specifier: workspace:ts-pattern__5.x@* version: link:../../vendor/ts-pattern@5.x @@ -783,13 +788,13 @@ importers: version: link:../../packages/vite-plugin-runtime '@storybook/react-vite': specifier: 'catalog:' - version: 10.5.6(esbuild@0.28.2)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)(rollup@4.61.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(typescript@6.0.3)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + version: 10.6.1(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)(rollup@4.61.1)(storybook@10.6.1(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(typescript@6.0.3)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.3.3(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + version: 4.3.3(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) '@tanstack/router-plugin': specifier: ^1.168.41 - version: 1.168.41(@tanstack/react-router@1.170.40(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(esbuild@0.28.2)(rollup@4.61.1)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + version: 1.168.41(@tanstack/react-router@1.170.40(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(esbuild@0.28.2)(rolldown@1.2.12)(rollup@4.61.1)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) '@testing-library/dom': specifier: 'catalog:' version: 10.4.2 @@ -801,7 +806,7 @@ importers: version: 1.5.6 '@vitejs/plugin-react-swc': specifier: ^4.3.3 - version: 4.3.3(@swc/helpers@0.5.23)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + version: 4.3.3(@swc/helpers@0.5.23)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) happy-dom: specifier: 'catalog:' version: 20.11.15 @@ -810,10 +815,10 @@ importers: version: 4.3.3 vite: specifier: 'catalog:' - version: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + version: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) vite-plugin-compression: specifier: ^0.5.1 - version: 0.5.1(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + version: 0.5.1(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) packages/demo: dependencies: @@ -833,8 +838,8 @@ importers: specifier: 'catalog:' version: 15.0.0 es-module-lexer: - specifier: ^2.3.2 - version: 2.3.2 + specifier: ^3.0.2 + version: 3.0.2 esbuild: specifier: 'catalog:' version: 0.28.2 @@ -1000,8 +1005,8 @@ importers: specifier: workspace:lodash-es__4.x@* version: link:../../vendor/lodash-es@4.x lucide-react: - specifier: ^0.577.0 - version: 0.577.0(react@vendor+react@19.x) + specifier: ^1.49.0 + version: 1.49.0(react@vendor+react@19.x) motion: specifier: 'catalog:' version: 13.4.4(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) @@ -1038,7 +1043,7 @@ importers: version: link:../instrument-stubs '@storybook/react-vite': specifier: 'catalog:' - version: 10.5.6(esbuild@0.28.2)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)(rollup@4.61.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(typescript@6.0.3)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + version: 10.6.1(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)(rollup@4.61.1)(storybook@10.6.1(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(typescript@6.0.3)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) '@testing-library/dom': specifier: 'catalog:' version: 10.4.2 @@ -1053,7 +1058,7 @@ importers: version: link:../../vendor/type-fest@4.x vite: specifier: 'catalog:' - version: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + version: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) packages/release-info: dependencies: @@ -1122,7 +1127,7 @@ importers: dependencies: '@casl/ability': specifier: 'catalog:' - version: 6.8.1 + version: 7.0.1 '@douglasneuroinformatics/libjs': specifier: 'catalog:' version: 3.2.1(neverthrow@8.2.0)(zod@vendor+zod@3.x) @@ -1224,7 +1229,7 @@ importers: version: link:../../runtime/v1 vite: specifier: 'catalog:' - version: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + version: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) runtime/v1: devDependencies: @@ -1384,25 +1389,25 @@ importers: version: link:../packages/vite-plugin-runtime '@storybook/addon-docs': specifier: 'catalog:' - version: 10.5.6(esbuild@0.28.2)(rollup@4.61.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + version: 10.6.1(storybook@10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)) '@storybook/addon-themes': specifier: 'catalog:' - version: 10.5.6(storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)) + version: 10.6.1(storybook@10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)) '@storybook/react-vite': specifier: 'catalog:' - version: 10.5.6(esbuild@0.28.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(rollup@4.61.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(typescript@6.0.3)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + version: 10.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(rollup@4.61.1)(storybook@10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(typescript@6.0.3)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.3.3(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + version: 4.3.3(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) esbuild-wasm: specifier: 'catalog:' version: 0.28.2 storybook: specifier: 'catalog:' - version: 10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) vite: specifier: 'catalog:' - version: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + version: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) testing: dependencies: @@ -1913,10 +1918,6 @@ packages: resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.29.7': - resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} - engines: {node: '>=6.9.0'} - '@babel/generator@7.29.8': resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==} engines: {node: '>=6.9.0'} @@ -1955,11 +1956,6 @@ packages: resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.7': - resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} - engines: {node: '>=6.0.0'} - hasBin: true - '@babel/parser@7.29.9': resolution: {integrity: sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==} engines: {node: '>=6.0.0'} @@ -1977,10 +1973,6 @@ packages: resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} engines: {node: '>=6.9.0'} - '@babel/types@7.29.7': - resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} - engines: {node: '>=6.9.0'} - '@babel/types@7.29.8': resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} engines: {node: '>=6.9.0'} @@ -2016,14 +2008,11 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} - '@blazediff/core@1.9.1': - resolution: {integrity: sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA==} - '@borewit/text-codec@0.2.2': resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} - '@cap.js/server@2.0.0': - resolution: {integrity: sha512-CaETNf+u/+vgkzQJu3Fq3UWrd8egUFYBFLYo5Rf5j2muIVY1syqUJbwvwxLbgE5mlMmND/RUo15D/G0iKCOIYA==} + '@cap.js/server@4.0.5': + resolution: {integrity: sha512-S902YIyGyiriNaexfqTzMy5ixxSb3/jYSJwr2gAY9d7XXoYftcifgij/11pjuiU72Ogm6XKZOggDB2DtjRMyww==} '@cap.js/widget@0.1.58': resolution: {integrity: sha512-snNjlYZLx1XddDH7DPZF9uedynSXTPPeRl/nExDlMjw0pCHiu/Fm1NKjRcT4HmqpOBf0TZRvio1HhkTMWg9p9A==} @@ -2032,14 +2021,14 @@ packages: resolution: {integrity: sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==} engines: {node: '>=18'} - '@casl/ability@6.8.1': - resolution: {integrity: sha512-VX5DD1JbSP/DdewZnNwXXaCzve+0pLe14mcUj2l93CdOFAQUT/ylAptNqxf3Wc/jlsuSanAgXza4Z1Iq23dzpQ==} + '@casl/ability@7.0.1': + resolution: {integrity: sha512-krOW1zQGEie5lH6fpryrcsPvc5r2pe5Vn5xbthuzc5X9gwzHIyZgGGgw9dMoSLHXdjB4BIVxGG/HBkG+1NuyZQ==} - '@casl/prisma@1.6.2': - resolution: {integrity: sha512-w0Y8pB/Zp5bSl5E3Ffn0tLazZ2GQZkL64lf+YDevoaDB1+K6RUOFCGVkvE3bYYv+qLYTgO261k99GufIJ4iHeg==} + '@casl/prisma@2.0.2': + resolution: {integrity: sha512-IYp9rABl8s9fF+4NubSahYMXqwLbmVCz8Hd9Xa4MbS6xMkSRTTa+tq9oKQFd/SJ6VoLe2oY+7Wg0eF9CjOCnYA==} peerDependencies: - '@casl/ability': ^5.3.0 || ^6.0.0 - '@prisma/client': ^2.14.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + '@casl/ability': ^7.0.0 + '@prisma/client': ^4.16.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 '@commander-js/extra-typings@13.1.0': resolution: {integrity: sha512-q5P52BYb1hwVWE6dtID7VvuJWrlfbCv4klj7BjUUOqMz4jbSZD4C9fJ9lRjL2jnBGTg+gDDlaXN51rkWcLk4fg==} @@ -2166,22 +2155,22 @@ packages: neverthrow: ^8.2.0 zod: ^3.25.67 || 4.x - '@douglasneuroinformatics/libnest@9.0.0': - resolution: {integrity: sha512-uVFJEin/mkhW+FvvGM0032qXpnv5T2astzAGCziesGvBGWAf6PG0TQptl5WQcNUIptdN+GR/O7co813jy8I5yQ==} - engines: {node: 22.x || 24.x} + '@douglasneuroinformatics/libnest@10.0.0': + resolution: {integrity: sha512-q3ZyuH9zVagdeMj7nthIA8/7p5pbci0c6tB+cWN//X3O1HwrHEt+TkXwsg/fRaBIglok9RB3qN4X6lBF3LKb8A==} + engines: {node: ^22.12.0 || 24.x} hasBin: true peerDependencies: - '@nestjs/common': ^11.0.11 - '@nestjs/core': ^11.0.11 - '@nestjs/platform-fastify': ^11.1.6 - '@nestjs/testing': ^11.0.11 + '@nestjs/common': ^12.0.0 + '@nestjs/core': ^12.0.0 + '@nestjs/platform-fastify': ^12.0.0 + '@nestjs/testing': ^12.0.0 '@prisma/client': ^6.9.0 - fastify: ^5.12.5 + fastify: ^5.12.1 neverthrow: ^8.2.0 - reflect-metadata: ~0.1.13 + reflect-metadata: ^0.2.2 rxjs: ^7.8.2 vite: '*' - vitest: 4.x + vitest: 5.x zod: ^3.25.x peerDependenciesMeta: vite: @@ -2265,13 +2254,13 @@ packages: tailwindcss: ^4.1.0 zod: ^3.25.x - '@douglasneuroinformatics/prettier-config@0.3.0': - resolution: {integrity: sha512-pa8AXwRQHmq99nbYsAfWjfk0MOT0sjidsfP0VMaWEvDQy4l055kLwggWa0aqc5C6V3ZubA56K4gx5+r3/drslQ==} + '@douglasneuroinformatics/prettier-config@0.4.0': + resolution: {integrity: sha512-uB8vV0ExwUPfxTxdTvyOmWOxIwIKt9KdTmUXwSErIbDb1nTJ1BWbb+jXSeWD22BjvBuSty8mC7B7SoB8PhPamA==} hasBin: true peerDependencies: husky: 9.x prettier: 3.x - prettier-plugin-astro: 0.x + prettier-plugin-astro: 0.x || 1.x prettier-plugin-svelte: 3.x prettier-plugin-tailwindcss: 0.x peerDependenciesMeta: @@ -2310,8 +2299,8 @@ packages: '@emmetio/stream-reader@2.2.0': resolution: {integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==} - '@emnapi/core@1.10.0': - resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + '@emnapi/core@1.11.0': + resolution: {integrity: sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q==} '@emnapi/core@1.11.2': resolution: {integrity: sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==} @@ -2322,6 +2311,9 @@ packages: '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + '@emnapi/runtime@1.11.0': + resolution: {integrity: sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==} + '@emnapi/runtime@1.11.2': resolution: {integrity: sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==} @@ -2860,8 +2852,8 @@ packages: '@expressive-code/plugin-text-markers@0.41.7': resolution: {integrity: sha512-Ewpwuc5t6eFdZmWlFyeuy3e1PTQC0jFvw2Q+2bpcWXbOZhPLsT7+h8lsSIJxb5mS7wZko7cKyQ2RLYDyK6Fpmw==} - '@faker-js/faker@10.2.0': - resolution: {integrity: sha512-rTXwAsIxpCqzUnZvrxVh3L0QA0NzToqWBLAhV+zDV3MIIwiQhAZHMdPCIaj5n/yADu/tyk12wIPgL6YHGXJP+g==} + '@faker-js/faker@10.6.0': + resolution: {integrity: sha512-3RQHgEtvL1Frl/d1cSreo7qhJ3Gk1OdNUai/CtZ8G+wYeRQnJih3s9xJ9/kgYekPQRdwgh0HXRPqMlzWGwivIQ==} engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'} '@fastify/ajv-compiler@4.0.5': @@ -2876,8 +2868,8 @@ packages: '@fastify/fast-json-stringify-compiler@5.0.3': resolution: {integrity: sha512-uik7yYHkLr6fxd8hJSZ8c+xF4WafPK+XzneQDPU+D10r5X19GW8lJcom2YijX2+qtFF1ENJlHXKFM9ouXNJYgQ==} - '@fastify/formbody@8.0.2': - resolution: {integrity: sha512-84v5J2KrkXzjgBpYnaNRPqwgMsmY7ZDjuj0YVuMR3NXCJRCgKEZy/taSP1wUYGn0onfxJpLyRGDLa+NMaDJtnA==} + '@fastify/formbody@9.0.0': + resolution: {integrity: sha512-T/af26CSrUARBCvsEmv+DJLPfZlrRKESzqironxP1j7qzuLyKcoZtj6MuTGShuKx1THXugoie2oFbUJxXfGFzA==} '@fastify/forwarded@3.0.1': resolution: {integrity: sha512-JqDochHFqXs3C3Ml3gOY58zM7OqO9ENqPo0UqAjAjH8L01fRZqwX9iLeX34//kiJubF7r2ZQHtBRU36vONbLlw==} @@ -2906,8 +2898,8 @@ packages: '@floating-ui/utils@0.2.11': resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} - '@gerrit0/mini-shiki@1.27.2': - resolution: {integrity: sha512-GeWyHz8ao2gBiUW4OJnQDxXQnFgZQwwQk05t/CVVgNBN7/rK8XZ7xY6YhLVv9tH3VppWWmr9DCl3MwemB/i+Og==} + '@gerrit0/mini-shiki@3.23.0': + resolution: {integrity: sha512-bEMORlG0cqdjVyCEuU0cDQbORWX+kYCeo0kV1lbxF5bt4r7SID2l9bqsxJEM0zndaxpOUT7riCyIVEuqq/Ynxg==} '@heroicons/react@2.2.0': resolution: {integrity: sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==} @@ -3142,6 +3134,9 @@ packages: '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} @@ -3254,22 +3249,9 @@ packages: '@microsoft/tsdoc-config@0.18.2': resolution: {integrity: sha512-4ymuLTQ9lFwJXK15f41iPcNHflymjk02Ltq5f5wo3fA02O1nHIGSc1TIZwzTSQZep+jXHM644jobt4Q8O3vtqg==} - '@microsoft/tsdoc@0.16.0': - resolution: {integrity: sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==} - '@microsoft/tsdoc@0.17.0': resolution: {integrity: sha512-p68VexhnH7ojf3U27RdryUDqnKJgKaWUbCL96vJR7N0mqDuhKG5OIECk3sCPPdynxjk+yoVhRkScqtv5KQjzsw==} - '@monaco-editor/loader@1.7.0': - resolution: {integrity: sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA==} - - '@monaco-editor/react@4.7.0': - resolution: {integrity: sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==} - peerDependencies: - monaco-editor: '>= 0.25.0 < 1' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@mongodb-js/saslprep@1.4.11': resolution: {integrity: sha512-o9rAHc0IpIjuPSxRutWpE1F62x7n+4mVS4rCNHkzhIUMQcc18bb6xEq5wd2NdN0WjepIyXIppRshYI2kQDOZVA==} @@ -3303,12 +3285,6 @@ packages: cpu: [x64] os: [win32] - '@napi-rs/wasm-runtime@1.1.4': - resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} - peerDependencies: - '@emnapi/core': ^1.7.1 - '@emnapi/runtime': ^1.7.1 - '@napi-rs/wasm-runtime@1.2.4': resolution: {integrity: sha512-AJxoUD2/15ESHbvpcyjU274nsAPLuOtPHCk0vKJM5pj//Fg/B1FXNWjPnXTT9PymCYYiHo4zPj0ZomXBKhoy7g==} engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} @@ -3324,8 +3300,8 @@ packages: axios: ^1.3.1 rxjs: ^7.0.0 - '@nestjs/common@11.2.6': - resolution: {integrity: sha512-uXs98qEOesTf6rGs0OcvFpRdF4M6JvzyBmoIXcTYvojdte4HiwDYv+whaALoboyfu/fuq2umF74FLQu3V7ZPHw==} + '@nestjs/common@12.1.1': + resolution: {integrity: sha512-foR+9SDz53vd4WXvN5UEXbcU0i/i9mf/zXqbAWlEDQlxAooS4kZoY5X/Zr2DsUJZaLPOk3kFQdu6EhbWrhAoDQ==} peerDependencies: class-transformer: '>=0.4.1' class-validator: '>=0.13.2' @@ -3337,14 +3313,14 @@ packages: class-validator: optional: true - '@nestjs/core@11.2.6': - resolution: {integrity: sha512-KZkwy6KBePPeT3EUj+NACVq6VLT5S+Msbc761NAVVyQ0FyOj7o4I85GEg/cdEPu6KdLqhJFfuqRW2SN+J2ZubQ==} + '@nestjs/core@12.1.1': + resolution: {integrity: sha512-wI6zlO7sfoL4532/XXVkdPSiiXPAUsFdUkK42bTxVKoaEj60x8y8k95HtxOy5q/tUcXcB2Q4HIFKwVjgMamHeg==} engines: {node: '>= 20'} peerDependencies: - '@nestjs/common': ^11.0.0 - '@nestjs/microservices': ^11.0.0 - '@nestjs/platform-express': ^11.0.0 - '@nestjs/websockets': ^11.0.0 + '@nestjs/common': ^12.0.0 + '@nestjs/microservices': ^12.0.0 + '@nestjs/platform-express': ^12.0.0 + '@nestjs/websockets': ^12.0.0 reflect-metadata: ^0.1.12 || ^0.2.0 rxjs: ^7.1.0 peerDependenciesMeta: @@ -3360,68 +3336,35 @@ packages: peerDependencies: '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0 - '@nestjs/mapped-types@2.1.1': - resolution: {integrity: sha512-SCCoMEJ6jdeI5h/N+KCVF1+pmg/hmEkNA5nHTS8Gvww7T/LCl4o1gFLinw2iQ60w7slFkszHcGLKGdazVI4F8A==} - peerDependencies: - '@nestjs/common': ^10.0.0 || ^11.0.0 - class-transformer: ^0.4.0 || ^0.5.0 - class-validator: ^0.13.0 || ^0.14.0 || ^0.15.0 - reflect-metadata: ^0.1.12 || ^0.2.0 - peerDependenciesMeta: - class-transformer: - optional: true - class-validator: - optional: true - '@nestjs/passport@12.0.0': resolution: {integrity: sha512-FM9ioo2Dyj+cC7aeO4g19ijAXoRaHlW/GQZFbgXsM4Z9pyQedA8yOseb7ivfqlPwUKJlH9PFgeWniu6c0vb6dw==} peerDependencies: '@nestjs/common': ^11.0.0 || ^12.0.0 passport: ^0.5.0 || ^0.6.0 || ^0.7.0 - '@nestjs/platform-express@11.2.6': - resolution: {integrity: sha512-jPypI/+aueizkYG2Bw2kg8GaNsWE7ekFBSQ/Rwet7wEdBA/+q2FA364UbDabqjlR7C3VSNHmP/JXh+8+jXyDOw==} - peerDependencies: - '@nestjs/common': ^11.0.0 - '@nestjs/core': ^11.0.0 - - '@nestjs/platform-fastify@11.2.6': - resolution: {integrity: sha512-Ynx21MFs2EHjebQkVG4fHWLJr3pcjA+45qv4+YbwPtETP7gLvsk955UPviKgcq4zil9tvE799qilz9BUxTISFQ==} + '@nestjs/platform-fastify@12.1.1': + resolution: {integrity: sha512-7w5Cm/bI2f4fly5VmOhtKv25bwM8LoLpWGCB0fzPCTDRnEosIbLO3mWhBRHGAdPWE/N52LS14L0w+1/ZzsdFqw==} peerDependencies: + '@fastify/multipart': ^10.1.0 '@fastify/static': ^10.1.2 '@fastify/view': ^10.0.0 || ^11.0.0 || ^12.0.0 - '@nestjs/common': ^11.0.0 - '@nestjs/core': ^11.0.0 + '@nestjs/common': ^12.0.0 + '@nestjs/core': ^12.0.0 peerDependenciesMeta: - '@fastify/static': + '@fastify/multipart': optional: true - '@fastify/view': - optional: true - - '@nestjs/swagger@11.4.4': - resolution: {integrity: sha512-VaIo1ruV2G7b+f2zPzkBSUNy9a/WQ9sg8TLKhWlrTfg4O6U10M/PA7Xi6XMXadOVhwOqoesijba8jH3i/3adrA==} - peerDependencies: - '@fastify/static': ^8.0.0 || ^9.0.0 - '@nestjs/common': ^11.0.1 - '@nestjs/core': ^11.0.1 - class-transformer: '*' - class-validator: '*' - reflect-metadata: ^0.1.12 || ^0.2.0 - peerDependenciesMeta: '@fastify/static': optional: true - class-transformer: - optional: true - class-validator: + '@fastify/view': optional: true - '@nestjs/testing@11.2.6': - resolution: {integrity: sha512-Oua8EUw3WsnSIwAMIpvyuJxOdUxHeX04fX5MsSIpjaft5CcNnbWhSmM/u/GDDOEcAOrxOfG/KHa7LzzWdS/bxw==} + '@nestjs/testing@12.1.1': + resolution: {integrity: sha512-kMCTifsIlvfdCs/4F495HY0tjmwHu0d5JoXpr9BsT8CJ1NScfbrx24mlkevFNpq26jTQKR5e82hOfqikad1gSg==} peerDependencies: - '@nestjs/common': ^11.0.0 - '@nestjs/core': ^11.0.0 - '@nestjs/microservices': ^11.0.0 - '@nestjs/platform-express': ^11.0.0 + '@nestjs/common': ^12.0.0 + '@nestjs/core': ^12.0.0 + '@nestjs/microservices': ^12.0.0 + '@nestjs/platform-express': ^12.0.0 peerDependenciesMeta: '@nestjs/microservices': optional: true @@ -3796,8 +3739,11 @@ packages: '@oxc-project/types@0.150.0': resolution: {integrity: sha512-rDS5/31E9HfPl/CIzGrn0DOlvBbXFseQ5URJ9sYMfstbKLD/c6Gm9vmRzRGDdAXyOIL4zmO37lc9RIwYqVruZw==} - '@oxc-resolver/binding-android-arm-eabi@11.20.0': - resolution: {integrity: sha512-IjfWOXRgJFNdORDl+Uf1aibNgZY2guOD3zmOhx1BGVb/MIiqlFTdmjpQNplSN58lhWehnX4UNqC3QwpUo8pjJg==} + '@oxc-project/types@0.152.0': + resolution: {integrity: sha512-oM/5rLBm2tPkg0iBgkH/FOeR3PCDpY19GTgAZjMFM8h9WI9VW7cLgzp6nwtarYKmovavIQZ+Fe/RKX/8C8O/Rw==} + + '@oxc-resolver/binding-android-arm-eabi@11.21.2': + resolution: {integrity: sha512-xQoCRv+gKax9KTdwdaQNnAFOai8neay7g3jExDIORzhbrejwGSJaZNTdOJHR5ziLg2joMxOCMOFMo4zuxza2uQ==} cpu: [arm] os: [android] @@ -3806,8 +3752,8 @@ packages: cpu: [arm] os: [android] - '@oxc-resolver/binding-android-arm64@11.20.0': - resolution: {integrity: sha512-QqslZAuFQG8Q9xm7JuIn8JUbvywhSBMVhuQHtYW+auirZJloS41oxUUaBXk7uUhZJgp44c5zQLeVvmFaDQB+2Q==} + '@oxc-resolver/binding-android-arm64@11.21.2': + resolution: {integrity: sha512-HF5oiE2L05yInPYCFD/4uxSrEZW4SuIfn99Y6L1xnJnzl066JR+MJs2rIdstw8A2MPlAKH+13dpFPNycjqzvGg==} cpu: [arm64] os: [android] @@ -3816,8 +3762,8 @@ packages: cpu: [arm64] os: [android] - '@oxc-resolver/binding-darwin-arm64@11.20.0': - resolution: {integrity: sha512-MUcavykj2ewlR+kc5arpg4tC2RvzJkUxWtNv74pf7lcNk00GpIpN43vXMj+j6r4eMmfZhlb8hueKoIb8e9kAGQ==} + '@oxc-resolver/binding-darwin-arm64@11.21.2': + resolution: {integrity: sha512-UX4u49CVCAD8QZNELaW8eMGgMAGwFWYEPbvNsh+3r/gs4NX3KfpiACMVwRQT0EuH3uat9hM5Zl+Ppm9pJD8tgg==} cpu: [arm64] os: [darwin] @@ -3826,8 +3772,8 @@ packages: cpu: [arm64] os: [darwin] - '@oxc-resolver/binding-darwin-x64@11.20.0': - resolution: {integrity: sha512-BGB16nRUK5Etiv//ihPyzj8Lj1px0mhh4YIfe0FDf045ywknfSm0GEbiRESpr6Q4K82AvnyaRIhhluHByvS4bg==} + '@oxc-resolver/binding-darwin-x64@11.21.2': + resolution: {integrity: sha512-J9xPx7YBkrRmJ+xl561ztnMWEc1aOyjEIxBiGX1dVb3u7bGSnfObfcZk+Pd+uM0HZAPNsQ1xvD8j52A/uOSqNQ==} cpu: [x64] os: [darwin] @@ -3836,8 +3782,8 @@ packages: cpu: [x64] os: [darwin] - '@oxc-resolver/binding-freebsd-x64@11.20.0': - resolution: {integrity: sha512-JZgtePaqj3qmD5XFHJaSLWzHRxQu0LaPkdoM1KJXYADvAaa83ijXHclV3ej3CueeW0wxfIAbGCZVP45J0CA7uQ==} + '@oxc-resolver/binding-freebsd-x64@11.21.2': + resolution: {integrity: sha512-fRlt7OvSaQkWj6+EDTVxawVxOlqJB2QSnBfkeCyK4RTvsGctbw3BiH2Tb7DzMs7bikc4BRBpvWP5zF9K8b54Zg==} cpu: [x64] os: [freebsd] @@ -3846,8 +3792,8 @@ packages: cpu: [x64] os: [freebsd] - '@oxc-resolver/binding-linux-arm-gnueabihf@11.20.0': - resolution: {integrity: sha512-hOQ/p3ry3v3SchUBXicrrnszaI/UmYzM4wtS4RGfwgVUX7a+HbyQSzJ5aOzu+o6XZkFkS3ZXN4PZAzhOb77OSg==} + '@oxc-resolver/binding-linux-arm-gnueabihf@11.21.2': + resolution: {integrity: sha512-gK+vPUcPQITkGwBKpZGrcDHSlU6eDGl7AQacxS2CEKAZIBHWkOVFeJwLZ4tYnA1acJqRM5lt7yYwPCVqGHIJ7A==} cpu: [arm] os: [linux] @@ -3856,8 +3802,8 @@ packages: cpu: [arm] os: [linux] - '@oxc-resolver/binding-linux-arm-musleabihf@11.20.0': - resolution: {integrity: sha512-2ArPksaw0AqeuGBfoS715VF+JvJQAhD2niWgjE5hVO+L+nAfikVQopvngCMX9x4BD8itWoQ3dnikrQyl5Ho5Jg==} + '@oxc-resolver/binding-linux-arm-musleabihf@11.21.2': + resolution: {integrity: sha512-L/Rgas7SrOKy/z7IH+HxSFRqVO4PuLDKLEGKvnhoCBBq3UJ0YzGBou3qMzaAGgkJwsIvX2pBF+7ojzfUhLiZxQ==} cpu: [arm] os: [linux] @@ -3866,8 +3812,8 @@ packages: cpu: [arm] os: [linux] - '@oxc-resolver/binding-linux-arm64-gnu@11.20.0': - resolution: {integrity: sha512-0bJnmYFp62JdZ4nVMDUZ/C58BCZOCcqgKtnUlp7L9Ojf/czIN+3j72YlLPeWLkzlr6SlYvIQA4SGV/HyO0d+qg==} + '@oxc-resolver/binding-linux-arm64-gnu@11.21.2': + resolution: {integrity: sha512-CUEYvlX1Fk7E9kUMzuswru1J9HLxMwnpDeQGjQuI4ZH+iNCoa2X9T+pvyzrbsgl7WnIeTFTlNlHsRfVdf5g9/g==} cpu: [arm64] os: [linux] libc: [glibc] @@ -3878,8 +3824,8 @@ packages: os: [linux] libc: [glibc] - '@oxc-resolver/binding-linux-arm64-musl@11.20.0': - resolution: {integrity: sha512-wKHHzPKZo7Ufhv/Bt6yxT7FOgnIgW4gwXcJUipkShGp68W3wGVqvr1Sr0fY65lN0Oy6y41+g2kIDvkgZaMMUkw==} + '@oxc-resolver/binding-linux-arm64-musl@11.21.2': + resolution: {integrity: sha512-ViN1ZibQyxwC67GpoP33oo+S9UyUnkog13vzQb9+v9bCNvrVzJuk0MRdacjtv/9xfRMVF/eqHFyl8YOeykI10Q==} cpu: [arm64] os: [linux] libc: [musl] @@ -3890,8 +3836,8 @@ packages: os: [linux] libc: [musl] - '@oxc-resolver/binding-linux-ppc64-gnu@11.20.0': - resolution: {integrity: sha512-RN8goF7Ie0B79L4i4G6OeBocTgSC56vJbQ65VJje+oXnldVpLnOU7j/AQ/dP94TcCS+Yh6WG8u3Qt4ETteXFNQ==} + '@oxc-resolver/binding-linux-ppc64-gnu@11.21.2': + resolution: {integrity: sha512-CU1sCqWnhGqYD5I1HedHk5pujrn7ssDkNB/AEQd/pd3D/EojVSgJUlpbafwIbyhia3PgIfkvdFpRPWSALzVumA==} cpu: [ppc64] os: [linux] libc: [glibc] @@ -3902,8 +3848,8 @@ packages: os: [linux] libc: [glibc] - '@oxc-resolver/binding-linux-riscv64-gnu@11.20.0': - resolution: {integrity: sha512-5l1yU6/xQEqLZRzxqmMxJfWPslpwCmBsdDGaBvABPehxquCXDC7dd7oraNdKSJUMDXSM7VvVj8H2D2FTjU7oWw==} + '@oxc-resolver/binding-linux-riscv64-gnu@11.21.2': + resolution: {integrity: sha512-jWVyZtIHca4Gb96x7dag+y69vlei7ffjrsveLkmf2ZhqEAz6ZSBnY1GWvgZUaZlwZP62A3xD092BW97Q5VGc+g==} cpu: [riscv64] os: [linux] libc: [glibc] @@ -3914,8 +3860,8 @@ packages: os: [linux] libc: [glibc] - '@oxc-resolver/binding-linux-riscv64-musl@11.20.0': - resolution: {integrity: sha512-xHEvkbgz6UC+A3JOyDQy76LkUaxsNSfIr3/GV8slwZsnuooJiIB34gzJfsyvR4JdCYNUUPsRJc/w/oWkODu+hg==} + '@oxc-resolver/binding-linux-riscv64-musl@11.21.2': + resolution: {integrity: sha512-LF29obFqNgBUgDX7rmUK7M4D0JQG5LxhYzn3xXmECcHU9aQAdWG7NiY052qybtesEdwHQXKNTWYQ7mTsybNvWg==} cpu: [riscv64] os: [linux] libc: [musl] @@ -3926,8 +3872,8 @@ packages: os: [linux] libc: [musl] - '@oxc-resolver/binding-linux-s390x-gnu@11.20.0': - resolution: {integrity: sha512-aWPDUUmSeyHvlW+SoEUd+JIJsQhVhu6a5tBpDRMu058naPAchTgAVGCFy35zjbnFlt0i8hLWziff6HX0D3LU4g==} + '@oxc-resolver/binding-linux-s390x-gnu@11.21.2': + resolution: {integrity: sha512-+NYcm+cCHBbtdQQ3A4phQTSuVRYnNHz7wrl9XRAPEovcdoqi0mb1K5ZOl+jN54ZD+q1zz3V0vltbFJmzecJKmw==} cpu: [s390x] os: [linux] libc: [glibc] @@ -3938,8 +3884,8 @@ packages: os: [linux] libc: [glibc] - '@oxc-resolver/binding-linux-x64-gnu@11.20.0': - resolution: {integrity: sha512-x2YeSimvhJjKLVD8KSu8f/rqU1potcdEMkApIPJqjZWN7c2Fpt4g2X32WDg1p+XDAmyT7nuQGe0vnhvXeLbH+g==} + '@oxc-resolver/binding-linux-x64-gnu@11.21.2': + resolution: {integrity: sha512-UQqZDdG2r2HhAOsZEgufkIWHPQ886IUyuJQkoZByvzhW8j51R4UNzGBJFkTiTnLhQnggwJRdJgFWK4uY6ZVIMw==} cpu: [x64] os: [linux] libc: [glibc] @@ -3950,8 +3896,8 @@ packages: os: [linux] libc: [glibc] - '@oxc-resolver/binding-linux-x64-musl@11.20.0': - resolution: {integrity: sha512-kcRLEIxpZefeYfLChjpgFf3ilBzRDZ+yobMrpRsQlSrxuFGtm3U6PMU7AaEpMqo3NfDGVyJJseAjnRLzMFHjwQ==} + '@oxc-resolver/binding-linux-x64-musl@11.21.2': + resolution: {integrity: sha512-3Q9PMRjalWkT6NZ4jfujuqTCFwoWErg3y3BnOgb544B8IMw4PktiwWOigMfOHNRLMghZeJ7hpfpZf4CP7rV7Og==} cpu: [x64] os: [linux] libc: [musl] @@ -3962,8 +3908,8 @@ packages: os: [linux] libc: [musl] - '@oxc-resolver/binding-openharmony-arm64@11.20.0': - resolution: {integrity: sha512-HHcfnApSZGtKhTiHqe8OZruOZe5XuFQH5/E0Yhj3u8fnFvzkM4/k6WjacUf4SvA0SPEAbfbgYmVPuo0VX/fIBQ==} + '@oxc-resolver/binding-openharmony-arm64@11.21.2': + resolution: {integrity: sha512-Eljeq3ndtyKhM+Es8LITi4Zl2htzuRZcrPMF3kMCsrILztvU6AjZ3FuEhHHKobPUB9rMpzLpJP5bDqXI7r+iog==} cpu: [arm64] os: [openharmony] @@ -3972,8 +3918,8 @@ packages: cpu: [arm64] os: [openharmony] - '@oxc-resolver/binding-wasm32-wasi@11.20.0': - resolution: {integrity: sha512-Tn0y1XOFYHNfK1wp1Z5QK8Rcld/bsOwRISQXfqAZ5IBpv8Gz1IvV39fUWNprqNdRizgcvFhOzWwFun2zkJsyBg==} + '@oxc-resolver/binding-wasm32-wasi@11.21.2': + resolution: {integrity: sha512-HGDbNsIywqc4LxU38+CTJNnB/6BF7rheWOJ259b4eE0aEnelYblC8x+1tEd63bp31fYne63RQz9Jb4yVnC7Yig==} engines: {node: '>=14.0.0'} cpu: [wasm32] @@ -3982,8 +3928,8 @@ packages: engines: {node: '>=14.0.0'} cpu: [wasm32] - '@oxc-resolver/binding-win32-arm64-msvc@11.20.0': - resolution: {integrity: sha512-qPi25YNPe4YenS8MgsQU2+bIFHxxpLx1LVna2444cEHqNPhNjvWf9zqj4aWE43H9LpAsTmkkAlA3eL5ElBU3mA==} + '@oxc-resolver/binding-win32-arm64-msvc@11.21.2': + resolution: {integrity: sha512-iWx25CBEgH49iE9q5coEGI/jb1jl5kkCY9z6U5Og67xCkQ/WFMDc2J5U78+AE91SUxM2NqSLhJC8/PLfWnImww==} cpu: [arm64] os: [win32] @@ -3992,8 +3938,8 @@ packages: cpu: [arm64] os: [win32] - '@oxc-resolver/binding-win32-x64-msvc@11.20.0': - resolution: {integrity: sha512-Wb14jWEW8huH6It9F6sXd9vrYmIS7pMrgkU6sxpLxkP+9z+wRgs71hUEhRpcn8FOXAFa27FVWfY2tRpbfTzfLw==} + '@oxc-resolver/binding-win32-x64-msvc@11.21.2': + resolution: {integrity: sha512-VPoCAhKvCQTlG7vxqaBXcmuvbh77BfnGXj8g0pbvVXpm1F/R8rDVwqIWcEbMzrI1JvJlm8v7T9uMVQb6UctMRg==} cpu: [x64] os: [win32] @@ -4960,6 +4906,113 @@ packages: '@radix-ui/rect@1.1.3': resolution: {integrity: sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw==} + '@reduxjs/toolkit@2.13.0': + resolution: {integrity: sha512-f6jwVRfwW30+tnllz4YcsHHpPYYOE7abcHkyUCovD+P7DyhdAI5prz2Fh/8TLhakjpN+7aIEion1s5L/tvlYlA==} + peerDependencies: + react: ^16.9.0 || ^17.0.0 || ^18 || ^19 + react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 + peerDependenciesMeta: + react: + optional: true + react-redux: + optional: true + + '@rolldown/binding-android-arm-eabi@1.2.12': + resolution: {integrity: sha512-dB/a1214qKfHMXCpgqR4OZT+jS4kTyEXbQGJPqzobt5EwH5rX080pxE37alt3RzvR1bf1Yz/yGqRfrYAxuPw0A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@rolldown/binding-android-arm64@1.2.12': + resolution: {integrity: sha512-7KHFgQ5VJxIHcLlrwrc3Xbds7oTNQT7Pgi9gQCJKrd2VGab/UksIOYp6VD8MzCstGxOKMgNamPwUCfxPdP1OHg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.2.12': + resolution: {integrity: sha512-3YIhqHD96nA5SaYNRBR16HnGv4oavZvXfD/ayHM+oYZ0WD/8lBAtf6zQua4kEyAvpqrluKXl0lnOBoiNby7x9w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.2.12': + resolution: {integrity: sha512-UuuJ35MFw4gmFOrE9pEqIV+K3syIKveph+Qc1/ljHZVdoDW4pz/JHR/eMVom+TZGl/5OOvGJOWaOCVt3ZfqhxA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.2.12': + resolution: {integrity: sha512-uMvssit0a4W+/7D8CbHUvG719mH3R2jwXAlh/XcPvuHTE0g++LymF88DCGNX0HM2rBOn0xrzgXktIB6fLSJBTQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.2.12': + resolution: {integrity: sha512-XcFu0R0xWnwzSf4IQgFH1rJIckPN1pLy2R+4r9IDB7Yfu/ys9cVqfa4pBrMHj7a3gl8mIR4nRNPg0e5IvEVs6g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.2.12': + resolution: {integrity: sha512-260UrKgn8tz39ak+SMDOirKzr7V04M9dWPw5llW00SwBivCZoWcRBKV1d8cXnRkUmSZA3BdiUmBHWk7734Ulpw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.2.12': + resolution: {integrity: sha512-5YK1I9SqDkbPgc1IA8BgDl34suqUS2q0KWnBrirm0E51YjOs6eo6dV6jbQfNE/argHRSvd0QUGgtpIoYx+WWpw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.2.12': + resolution: {integrity: sha512-Rkcrmp7eFRg74yL5fXEU91JEWbdEPLevWwGtXpmhbjlD1StScbWTmO94Bhly+Mo+ketKYkdmM1vNUKeWSlx8cQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.2.12': + resolution: {integrity: sha512-qvK4DuAsQc2BSjlx+Xr+IzOIvvxbGZqxFwdWfG6F518Erj0GGISyQbJ6pIappnOxlNPzNHvo/L0BwB30GZ+zVw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.2.12': + resolution: {integrity: sha512-Q9uLBO53Xd4QIq1WOycVQyPP1O4HhraEV2qqb3uTrnVw6QZih9duY4vNXOivL1xoUS1/z+W8eF4NMfl2a8Sdjw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.2.12': + resolution: {integrity: sha512-3IBxWFMjbOZskDPKv8Lf9BCnahlKuHthWkYnyIxOH/QcJrFcS4EmcenthApkwr/5+nEqZlLzeYbxeMaX7A5u4g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.2.12': + resolution: {integrity: sha512-xtX61xg4LKPkPWilZU1ynKClz5Gj4bf74LML4r3eVLWumKnGjoEr1OSHQhMdbBDoYTi+yjrujvpZe2pUnqCrrA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-win32-arm64-msvc@1.2.12': + resolution: {integrity: sha512-At7fPB6PCaIjzgIhEZFxuT+BBFqiQibJDT4d3PhiR3f4E7bbMZF4aKblbFfEM3sETRDd1YiQx/+U/g/B/ou5Ew==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.2.12': + resolution: {integrity: sha512-WIw2haVKwjuYdXkHaoC0mF8Le71TuCBxjrdKqLbJGctbBABj+ClfmNvtbOnzpq3RokNo5+V1qhtSzJyXorsklQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} @@ -5146,18 +5199,12 @@ packages: resolution: {integrity: sha512-9oUS23ebDfbl8ED6CANdQ3qqBc/xhrQvzhQAv61oN391FvNRww6RzdUbo97NEXaMm7lNEQsTjdE3zqtgiMv/eQ==} engines: {node: '>=20.9.0'} - '@scarf/scarf@1.4.0': - resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==} - '@shikijs/core@3.23.0': resolution: {integrity: sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==} '@shikijs/engine-javascript@3.23.0': resolution: {integrity: sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==} - '@shikijs/engine-oniguruma@1.29.2': - resolution: {integrity: sha512-7iiOx3SG8+g1MnlzZVDYiaeHe7Ez2Kf2HrJzdmGwkRisT7r4rak0e655AcM/tF9JG/kg5fMNYlLLKglbN7gBqA==} - '@shikijs/engine-oniguruma@3.23.0': resolution: {integrity: sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==} @@ -5167,9 +5214,6 @@ packages: '@shikijs/themes@3.23.0': resolution: {integrity: sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==} - '@shikijs/types@1.29.2': - resolution: {integrity: sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw==} - '@shikijs/types@3.23.0': resolution: {integrity: sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==} @@ -5276,44 +5320,29 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@storybook/addon-docs@10.5.6': - resolution: {integrity: sha512-zyUJBrrpC9NTrmsREaVFNr+9WW6pikJtmRvo7GgZGqthEyhjQKSarHrW0aNWkwae2ep3jp1CZi8vIUVG1Dnp0w==} + '@standard-schema/utils@0.3.0': + resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} + + '@storybook/addon-docs@10.6.1': + resolution: {integrity: sha512-31PXR+MCWfI5YHKKah6tWnbV1FJWA9qbTHxtvpszPLd8FBekXtPOnmyYOpFF9CfciBF9bkeJFdFanJvUCjWbjA==} peerDependencies: '@types/react': '*' - storybook: ^10.5.6 + storybook: ^10.6.1 peerDependenciesMeta: '@types/react': optional: true - '@storybook/addon-themes@10.5.6': - resolution: {integrity: sha512-fIzu2f6xPh/mtOBUU9TnjSoO3qUIF57AVES9HX4dfhjtbz9lWd+EhNd65nZfmTXxKsS32x/7/aXDTHtuP/ObwQ==} + '@storybook/addon-themes@10.6.1': + resolution: {integrity: sha512-SVZSM+mIiyK56d/3mRpRwPkAlpr9fdSSz/XpkT6fzI1PYFWDGSdElu2YmauzhaFGnlmAKL//tmXVvHXD4qCkIQ==} peerDependencies: - storybook: ^10.5.6 + storybook: ^10.6.1 - '@storybook/builder-vite@10.5.6': - resolution: {integrity: sha512-Ts8EohKPj8okDPCkueeKVN+IRGNpI3LuddsFGupqraRvK6aRWawDKA28uc0PlsLCLWbMkMsGVw+IpFXfmoLJgQ==} + '@storybook/builder-vite@10.6.1': + resolution: {integrity: sha512-kUMRRRS4MpJdxOLhrlQX3cpMYi2vVB3tIIRXyqWmAjVM6xT7OZ1SCQEMFPP+S3ToRqaYWZQb8aBqrJucbbYufA==} peerDependencies: - storybook: ^10.5.6 + storybook: ^10.6.1 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@storybook/csf-plugin@10.5.6': - resolution: {integrity: sha512-PJLyOmcKe1OZDBw7RaGX/gjuiJuVfS5pVgc4W2RnHYOFpU6F5Bv9+9MqQwp0i7tWZBWc4fsCJudgVqwgjuTROA==} - peerDependencies: - esbuild: '*' - rollup: '*' - storybook: ^10.5.6 - vite: '*' - webpack: '*' - peerDependenciesMeta: - esbuild: - optional: true - rollup: - optional: true - vite: - optional: true - webpack: - optional: true - '@storybook/global@5.0.0': resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} @@ -5323,40 +5352,40 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@storybook/react-dom-shim@10.5.6': - resolution: {integrity: sha512-dV3oOHc5ImggxEqeIiUj4vvnQO5SKScFtqAkxgIWLju1wiSZSIqQ5Q4Mp12Rhs9hQrjF039DueH7f2xJJZfvSw==} + '@storybook/react-dom-shim@10.6.1': + resolution: {integrity: sha512-OkPFycR6kVE+9ZsgQWRqnUfZm/sLY6dxsNAn3lsvV7DSAQWH9QnHLkqP9E/N/Hg6cKPDtGzDZ8vPNDz2FuaDuQ==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.5.6 + storybook: ^10.6.1 peerDependenciesMeta: '@types/react': optional: true '@types/react-dom': optional: true - '@storybook/react-vite@10.5.6': - resolution: {integrity: sha512-DCTfNZWhQUH4Zf8LDE4zdLn6+C26QNW0KETdnFUkdrqRADlwS6oExtGWC5f/uP/GDbKb9jrGbC+/ap8nWEH/vQ==} + '@storybook/react-vite@10.6.1': + resolution: {integrity: sha512-oyUZxuW2lIJN8BRbYyMyZbfjeYqtF6HwmNfqa1SAF525zRnMewYp66wm/5d8FAgwqejOf6N2+wR3hX866lSwMA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.5.6 + storybook: ^10.6.1 typescript: 6.0.x vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - '@storybook/react@10.5.6': - resolution: {integrity: sha512-dXSdNoc9yAvpa4hiegQhmZPXOKunAxkPX94DxvRw/kM6+wujVFAGlZjYygKrWw357KOjPRK7SO1LRTc70mgrhQ==} + '@storybook/react@10.6.1': + resolution: {integrity: sha512-t0QIzO0MVcpD52UEMZKSv35nO/+8vUnLGoFC1E3BIVjHEIdr6IFFM7ty2E7FWsaZGsah3XrFINKT3dPd2Atz+Q==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.5.6 + storybook: ^10.6.1 typescript: 6.0.x peerDependenciesMeta: '@types/react': @@ -5714,8 +5743,8 @@ packages: '@types/react-dom': optional: true - '@testing-library/user-event@14.6.1': - resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} + '@testing-library/user-event@14.6.7': + resolution: {integrity: sha512-MPCpX8bxe8zS+JmmTwLp8jd0dy1rAm60Te/SL8JrQM3qvQJcBOs1d7IefJMyZzqM3EWBrDn/LWDt1BCGu4ASfg==} engines: {node: '>=12', npm: '>=6'} peerDependencies: '@testing-library/dom': '>=7.21.4' @@ -5760,9 +5789,6 @@ packages: cpu: [arm64] os: [win32] - '@tybys/wasm-util@0.10.2': - resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} - '@tybys/wasm-util@0.10.4': resolution: {integrity: sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==} @@ -5880,9 +5906,6 @@ packages: '@types/nlcst@2.0.3': resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==} - '@types/node@22.19.21': - resolution: {integrity: sha512-VMeFBSCKQKmm2swI2kW51SFusDqekC6q9trBCvJ/JliDchFSuoYYKN7yVNjPthP1HKZcx3U1gI/wTcEBjEFKTA==} - '@types/node@24.19.0': resolution: {integrity: sha512-zY+5tKxXdhGh1PYI0ac+7juvEu4OI6vWtVVoj5i2m42jxAY1U+zHGt6QCyOFwykdP62sM3MJ9stoYYUw5aCWew==} @@ -5934,6 +5957,9 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/use-sync-external-store@0.0.6': + resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} + '@types/webidl-conversions@7.0.3': resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} @@ -6005,17 +6031,17 @@ packages: resolution: {integrity: sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@ucast/core@1.10.2': - resolution: {integrity: sha512-ons5CwXZ/51wrUPfoduC+cO7AS1/wRb0ybpQJ9RrssossDxVy4t49QxWoWgfBDvVKsz9VXzBk9z0wqTdZ+Cq8g==} + '@ucast/core@2.0.0': + resolution: {integrity: sha512-4XVx6LzPXZGvnZO5jp39cm/G4UvuwvEdtmg+9+4+zl6uFkCcB7UJacvtMYeBE56GJVT99Zqy6Pii7dGJq3Kz9Q==} - '@ucast/js@3.1.0': - resolution: {integrity: sha512-eJ7yQeYtMK85UZjxoxBEbTWx6UMxEXKbjVyp+NlzrT5oMKV5Gpo/9bjTl3r7msaXTVC8iD9NJacqJ8yp7joX+Q==} + '@ucast/js@4.0.1': + resolution: {integrity: sha512-9O5xPBvwEWQk2WvO69Eh2WJB8QljVZ2vRVdFvfnKjlZwWXcYxp1lqLBhwXBU1AtuSgCvKhJPkXdjKJggUmAmQQ==} - '@ucast/mongo2js@1.4.1': - resolution: {integrity: sha512-9aeg5cmqwRQnKCXHN6I17wk83Rcm487bHelaG8T4vfpWneAI469wSI3Srnbu+PuZ5znWRbnwtVq9RgPL+bN6CA==} + '@ucast/mongo2js@2.0.0': + resolution: {integrity: sha512-vNBZzRnsfLr/TSxEoxz6W6hHQ5tmWsfEeC0nCq5z8RezC1AqIRy3cfHm8AGvlGtcn+cTSFQcZremfqnz6wm+nQ==} - '@ucast/mongo@2.4.3': - resolution: {integrity: sha512-XcI8LclrHWP83H+7H2anGCEeDq0n+12FU2mXCTz6/Tva9/9ddK/iacvvhCyW6cijAAOILmt0tWplRyRhVyZLsA==} + '@ucast/mongo@3.0.0': + resolution: {integrity: sha512-kwuSH+kdB4GCR0LGhy/PEDm4PCflur89AlK82kNiYD0FvsA8A/p+0sx7m+/R8mMFAlmlkAd3VXp7sM/cLLYWYg==} '@ungap/structured-clone@1.3.1': resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} @@ -6026,16 +6052,11 @@ packages: peerDependencies: vite: ^4 || ^5 || ^6 || ^7 || ^8 - '@vitest/browser@4.1.11': - resolution: {integrity: sha512-bwMovvAeuTFOK5kIFevw4VEf+1gVEICv4SYK4k3knJOxl6b1zEWud8mYKD73e1B0odAn174h1MofURy2TPWf3w==} - peerDependencies: - vitest: 4.1.11 - - '@vitest/coverage-v8@4.1.11': - resolution: {integrity: sha512-8MVGEFnJIcdGjcbfKmeq8z0pZHH0JlVtoVZH9Q/qwUp6wyFnEJUBMrw9DCaj+ra3vShGmhavjalMIhPNxZAUcw==} + '@vitest/coverage-v8@5.0.2': + resolution: {integrity: sha512-3ffHBEi8DOOBLwIGBhOBZbRfYFYWjMUuxZicONdhuFEFEG5AVsMOSrVeuROskqnqpbOmEJwxM2eTVZ9N3a1t+A==} peerDependencies: - '@vitest/browser': 4.1.11 - vitest: 4.1.11 + '@vitest/browser': 5.0.2 + vitest: 5.0.2 peerDependenciesMeta: '@vitest/browser': optional: true @@ -6043,11 +6064,16 @@ packages: '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - '@vitest/expect@4.1.11': - resolution: {integrity: sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==} + '@vitest/istanbul-lib-coverage@1.0.2': + resolution: {integrity: sha512-9J/JMwOf9AoJhAywhrn7ScKTL38hsWQP/qPG60OtaAFcQ5OXPwKsxZFlbnuCKmZ61m8/lGgHYnFpdyQZUvG/iA==} + engines: {node: '>=22'} + + '@vitest/istanbul-lib-report@1.0.2': + resolution: {integrity: sha512-gUsfXZJbzPamoIY5TvHFiMMoXESBrUMo+xqaj+rYrWI69+EnvRlYBlP96ZnHPY4vX8kyUpgAnFUCg5wZG/HkDQ==} + engines: {node: '>=22'} - '@vitest/mocker@4.1.11': - resolution: {integrity: sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==} + '@vitest/mocker@5.0.2': + resolution: {integrity: sha512-Z5FS00Q1SJHkB35xATsmWGdQ5WA1/0MV3CDjqyv7GavHv1OfOj145MNfHOlHk7QLes21dKFDHr8EO2zvL+9WGA==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -6060,27 +6086,15 @@ packages: '@vitest/pretty-format@3.2.4': resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - '@vitest/pretty-format@4.1.11': - resolution: {integrity: sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==} - - '@vitest/runner@4.1.11': - resolution: {integrity: sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==} - - '@vitest/snapshot@4.1.11': - resolution: {integrity: sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==} - '@vitest/spy@3.2.4': resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} - '@vitest/spy@4.1.11': - resolution: {integrity: sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==} + '@vitest/spy@5.0.2': + resolution: {integrity: sha512-Ijc7T1nT9efNb5LxvjaBrEqw3f/QwUv5EE0nKqZxgqsaV/FxAAZ8baGylA8X/Z2oS4Lp+K74Jr6dTJsDKxJDeg==} '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} - '@vitest/utils@4.1.11': - resolution: {integrity: sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==} - '@volar/kit@2.4.28': resolution: {integrity: sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg==} peerDependencies: @@ -6207,9 +6221,6 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} - append-field@1.0.0: - resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} - are-docs-informative@0.0.2: resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} engines: {node: '>=14'} @@ -6287,8 +6298,8 @@ packages: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} - ast-v8-to-istanbul@1.0.3: - resolution: {integrity: sha512-jCMQ6ZylLPudp0CDfBmQBZUsrh1/8psbmu9ibeVWKuHWD0YrH9YABwlKu5kVEFoT0GCQQW9Z/SxfuEbbkGQCRg==} + ast-v8-to-istanbul@1.0.7: + resolution: {integrity: sha512-kFL68AG6ajd8fg248zwM9GQrUWEp79gsmjum34OEXjs4yHuUMZfYKwOLW9GMmB4oNvVrj+EAGxsP7ye2UR9UlA==} astring@1.9.0: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} @@ -6455,9 +6466,6 @@ packages: brace-expansion@1.1.15: resolution: {integrity: sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==} - brace-expansion@2.1.1: - resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==} - brace-expansion@5.0.6: resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} engines: {node: 18 || 20 || >=22} @@ -6489,10 +6497,6 @@ packages: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} - busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} - bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -6755,10 +6759,6 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - cors@2.8.6: - resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} - engines: {node: '>= 0.10'} - cosmiconfig-typescript-loader@6.3.0: resolution: {integrity: sha512-Akr82WH1Wfqatyiqpj8HDkO2o2KmJRu1FhKfSNJP3K4IdXwHfEyL7MOb62i1AGQVLtIQM+iCE9CGOtrfhR+mmA==} engines: {node: '>=v18'} @@ -7031,9 +7031,6 @@ packages: dom-accessibility-api@0.6.3: resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} - dom-helpers@5.2.1: - resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} - dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} @@ -7044,12 +7041,12 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - dompurify@3.1.7: - resolution: {integrity: sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==} - dompurify@3.4.12: resolution: {integrity: sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==} + dompurify@3.4.15: + resolution: {integrity: sha512-EUBjM+B+lkDE41iE82DDSCfkoPGfXx8IxFxPMjNzm/Uk4xDet77rTN9wqlxlVg71kK7XGuUMv6wUxJUwwv+Xyw==} + domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -7152,12 +7149,12 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - es-module-lexer@2.1.0: - resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} - es-module-lexer@2.3.2: resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} + es-module-lexer@3.0.2: + resolution: {integrity: sha512-BuIB67FngDSyQ/dpQNOZybwdEBDUGJQvOqwWr4ha/ufYiqzuEwPkKO2zLhRAgay28tStRIHUeWmszZAJo3GCOg==} + es-object-atoms@1.1.2: resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} engines: {node: '>= 0.4'} @@ -7409,9 +7406,6 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} - eventemitter3@4.0.7: - resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} - eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} @@ -7449,10 +7443,6 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-equals@5.4.0: - resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==} - engines: {node: '>=6.0.0'} - fast-fifo@1.3.2: resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} @@ -7488,9 +7478,6 @@ packages: resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} engines: {node: '>= 4.9.1'} - fastify-plugin@5.1.0: - resolution: {integrity: sha512-FAIDA8eovSt5qcDgcBvDuX/v0Cjz0ohGhENZ/wpc3y+oZCY2afZ9Baqql3g/lC+OHRnciQol4ww7tuthOb9idw==} - fastify-plugin@6.0.0: resolution: {integrity: sha512-fZOty7z3O7vOliF6d8bHE3wiEh1KcNnKEQensSgTk9C1DvN6nRLS++XVd86v33Hw/8u9Un8A1zDrQ8ujcQDHEg==} @@ -7524,9 +7511,9 @@ packages: resolution: {integrity: sha512-v0g/PTeuQgvKCBrVRsfVudvwXlRHSWHEQkVgKawgCGHkEpKA1clp3Om5jvEVhz8G9W/mOYjJH9FhkH4C888PgQ==} engines: {node: '>= 22'} - file-type@21.3.4: - resolution: {integrity: sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==} - engines: {node: '>=20'} + file-type@22.1.1: + resolution: {integrity: sha512-sEB0oStmeLGtpmSAD88RDNuLsvhv4iC3u0lE25CUvfCULvj49xoQ3l3K525Vn+ZzsZ6DOLajQCV6RmhwwhqiJg==} + engines: {node: '>=22'} fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} @@ -7587,10 +7574,6 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} - engines: {node: '>= 6'} - form-data@4.0.6: resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} engines: {node: '>= 6'} @@ -7861,9 +7844,6 @@ packages: resolution: {integrity: sha512-f7FxrlBz5FGd/J7tx9DR1cCQNIzKTl4BLZzgRXeQblzcO/xiWGrvXBMwztRzjJVeFACpED6P+iVmU7of9eFqyA==} engines: {node: '>= 20.19.0'} - html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - html-escaper@3.0.3: resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} @@ -8140,18 +8120,6 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - istanbul-lib-coverage@3.2.2: - resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} - engines: {node: '>=8'} - - istanbul-lib-report@3.0.1: - resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} - engines: {node: '>=10'} - - istanbul-reports@3.2.0: - resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} - engines: {node: '>=8'} - iterare@1.2.1: resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} engines: {node: '>=6'} @@ -8191,14 +8159,14 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} - hasBin: true - js-yaml@4.3.2: resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==} hasBin: true + js-yaml@5.4.2: + resolution: {integrity: sha512-m+aqu+LwO1O6sIopafj8HUVl5aawITwZQe/yHpMCKjaWBaA/d07B/QdMb3529REftiU+RMMHL3Vlsw3hON7vWg==} + hasBin: true + jsdoc-type-pratt-parser@4.1.0: resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==} engines: {node: '>=12.0.0'} @@ -8321,30 +8289,60 @@ packages: cpu: [arm64] os: [android] + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + lightningcss-darwin-arm64@1.32.0: resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + lightningcss-darwin-x64@1.32.0: resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + lightningcss-freebsd-x64@1.32.0: resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + lightningcss-linux-arm-gnueabihf@1.32.0: resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + lightningcss-linux-arm64-gnu@1.32.0: resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} engines: {node: '>= 12.0.0'} @@ -8352,6 +8350,13 @@ packages: os: [linux] libc: [glibc] + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + lightningcss-linux-arm64-musl@1.32.0: resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} @@ -8359,6 +8364,13 @@ packages: os: [linux] libc: [musl] + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} @@ -8366,6 +8378,13 @@ packages: os: [linux] libc: [glibc] + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} @@ -8373,22 +8392,45 @@ packages: os: [linux] libc: [musl] + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + lightningcss-win32-arm64-msvc@1.32.0: resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + lightningcss-win32-x64-msvc@1.32.0: resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + lightningcss@1.32.0: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} + engines: {node: '>= 12.0.0'} + lilconfig@2.1.0: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} engines: {node: '>=10'} @@ -8396,8 +8438,8 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - linkify-it@5.0.1: - resolution: {integrity: sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==} + linkify-it@5.0.2: + resolution: {integrity: sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==} load-esm@1.0.3: resolution: {integrity: sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==} @@ -8442,9 +8484,6 @@ packages: lodash.once@4.1.1: resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} - lodash@4.18.1: - resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} - longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -8462,15 +8501,14 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lucide-react@0.577.0: - resolution: {integrity: sha512-4LjoFv2eEPwYDPg/CUdBJQSDfPyzXCRrVW1X7jrx/trgxnxkHFjnVZINbzvzxjN70dxychOfg+FTYwBiS3pQ5A==} - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - lucide-react@1.17.0: - resolution: {integrity: sha512-9FA9evdox/JQL5PT57fdA1x/yg8T7knJ98+zjTL3UfKza6pflQUUh3XtaQIHKvnsJw1lmsEyHVlt5jchYxOQ5w==} + lucide-react@1.49.0: + resolution: {integrity: sha512-ApfaNM4/7jBrVopqLJ84Jz8TMQ1Q1JeZ1PmKh25aeS3E1FTVcMkSh1bEQB7dfzdIrwXRP8p3z4AJjTIHHb5IIA==} peerDependencies: + '@types/react': '*' react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true lunr@2.3.9: resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} @@ -8485,23 +8523,25 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + magic-string@1.4.2: + resolution: {integrity: sha512-vG+rjFRj1PqdIBozIxAGMjPlOhaVe+GXpbttY/iSK7rGcJRMlwNJO7dcUwmUqkymsFLJiNGI06t4D7Fr7yRC9g==} + magicast@0.5.3: resolution: {integrity: sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==} + magicast@0.5.5: + resolution: {integrity: sha512-UicdXN8zQ3JHlxVq+28afMXPr1z7WNY6+7EJnzTdQWkTAlMLF5fNCCKxJHBQwGaNGR11581EiQmQzx73+MvszA==} + make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} - make-dir@4.0.0: - resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} - engines: {node: '>=10'} - markdown-extensions@2.0.0: resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} engines: {node: '>=16'} - markdown-it@14.2.0: - resolution: {integrity: sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==} + markdown-it@14.3.2: + resolution: {integrity: sha512-sHHjZ5fJKlgrG4qns2YwVcdNep35h5fERrfkD2YNsb9UFk0UIHarbiTaHKVMlPuWAoiilyK8Fv/jAm11slsY7Q==} hasBin: true markdown-table@3.0.4: @@ -8579,10 +8619,6 @@ packages: mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} - media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} - media-typer@1.1.0: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} @@ -8750,10 +8786,6 @@ packages: minimatch@3.1.5: resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - minimatch@9.0.9: - resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} - engines: {node: '>=16 || 14 >=14.17'} - minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -8761,8 +8793,8 @@ packages: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} - monaco-editor@0.54.0: - resolution: {integrity: sha512-hx45SEUoLatgWxHKCmlLJH81xBo0uXP4sRkESUpmDQevfi+e7K1VuiSprK6UpQ8u4zOcKNiH0pMvHvlMWA/4cw==} + monaco-editor@0.57.0: + resolution: {integrity: sha512-5BkI9KGoqrNvBGUe15/QlZq3OooZ8WLg1AxTpaqHRCP3HNpzPPZKE2EDz8M7c+VRmCeUw1Brp4cx/PWm3kI/5A==} mongodb-connection-string-url@7.0.2: resolution: {integrity: sha512-ZoS07RoFqpKYQwAk59qmrx8+jJHNHU30UjlU96QktiGn1ltvDr+vCznLX5DiUBLEpMAHatHNWV1nM/74ul66kA==} @@ -8887,10 +8919,6 @@ packages: muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} - multer@2.4.0: - resolution: {integrity: sha512-7dqa0ZcFfzbefdTuIkzOSMvZWC0J7FLqBOjJUZvDCXShIURWKxAyTT1wHhnE5q19c7jOJf43IYYKjBmZVZmvhg==} - engines: {node: '>= 10.16.0'} - nanoid@3.3.19: resolution: {integrity: sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -9007,8 +9035,8 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} - obug@2.1.2: - resolution: {integrity: sha512-AWGB9WFcRXOQs48Z/udjI5ZcZMHXwX8XPByNpOydgcGsDLIzjGizhoMWJyKAWze7AVW/2W1i+/gPX4YtKe5cyg==} + obug@2.2.1: + resolution: {integrity: sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==} engines: {node: '>=12.20.0'} ofetch@1.5.1: @@ -9058,8 +9086,8 @@ packages: resolution: {integrity: sha512-zwajKw1GUa57IOdafIS7/yOObGF2NihwIfZfs5yJTRprMSkiwhWOc/k+n8bwnUPbHr2/XsjfBO8KyTPaW3VpWg==} engines: {node: ^20.19.0 || >=22.12.0} - oxc-resolver@11.20.0: - resolution: {integrity: sha512-CblytBiV/a/ZXY34dsVU2NxhIOxMXst8CvDCtyBelVITgd7PLrKzbEbA6oKLdPjvDKDzCiW48qzmzZ+mYaqn+g==} + oxc-resolver@11.21.2: + resolution: {integrity: sha512-w5tLwYN3Zo24w5EeWJjJWZOwhYqTtC8PS2B1tIt7BZUuqTIcU07sQValbDw+rq7+AuAGzOHklgK+ifsy4lpXfw==} oxc-resolver@11.24.2: resolution: {integrity: sha512-FY91FiDBj7ls5MsFS9jN3tjz2o0/zsdSsymlakySaBwVJZorHhkWyICLZMKxlu1R9vYo+sd3z1jwb4J8x7bNDw==} @@ -9246,10 +9274,6 @@ packages: resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} engines: {node: '>=10.13.0'} - pngjs@7.0.0: - resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} - engines: {node: '>=14.19.0'} - possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -9526,8 +9550,20 @@ packages: react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-is@19.1.0: + resolution: {integrity: sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==} + + react-redux@9.3.0: + resolution: {integrity: sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==} + peerDependencies: + '@types/react': '*' + react: ^18.0 || ^19 + redux: ^5.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + redux: + optional: true react-remove-scroll-bar@2.3.8: resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} @@ -9555,17 +9591,11 @@ packages: react: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - react-resizable-panels@3.0.6: - resolution: {integrity: sha512-b3qKHQ3MLqOgSS+FRYKapNkJZf5EQzuf6+RLiq1/IlTHw99YrZ2NJZLk4hQIzTnnIkRg2LUqyVinu6YWWpUYew==} - peerDependencies: - react: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - - react-smooth@4.0.4: - resolution: {integrity: sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==} + react-resizable-panels@4.14.1: + resolution: {integrity: sha512-OB1bXDNTLcGgTTbaX6Dn5efZhlMboSnkfr1w4xpsJTHPEbRJpACBhXpgRCXozgPO1ztgFeZRUe5J3mFNCVKm5g==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 react-style-singleton@2.2.3: resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} @@ -9577,12 +9607,6 @@ packages: '@types/react': optional: true - react-transition-group@4.4.5: - resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} - peerDependencies: - react: '>=16.6.0' - react-dom: '>=16.6.0' - react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -9616,16 +9640,13 @@ packages: resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} engines: {node: '>= 4'} - recharts-scale@0.4.5: - resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==} - - recharts@2.15.4: - resolution: {integrity: sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==} - engines: {node: '>=14'} - deprecated: 1.x and 2.x branches are no longer active. Bump to Recharts v3 to receive latest features and bugfixes. See https://github.com/recharts/recharts/wiki/3.0-migration-guide + recharts@3.10.1: + resolution: {integrity: sha512-QXFrvt6IVcw7eeZCoyXTwkIJAX3Dv1nyVhMicXJ47GsGDDpcN8z6o644DibE9XjpBTThtsomLKnTV6lc+cVFUA==} + engines: {node: '>=18'} peerDependencies: - react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-is: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 recma-build-jsx@1.0.0: resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==} @@ -9645,8 +9666,16 @@ packages: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} - reflect-metadata@0.1.14: - resolution: {integrity: sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==} + redux-thunk@3.1.0: + resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==} + peerDependencies: + redux: ^5.0.0 + + redux@5.0.1: + resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} + + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} @@ -9775,6 +9804,11 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rolldown@1.2.12: + resolution: {integrity: sha512-8wafseiaG80xmXSfqidUNqZcylTlhmPZZt+za2m+js2sFZ8dTNlhIOV2WcbIPx2hgwPBJpEUGFAMZ9bgBBLTSQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rollup@4.61.1: resolution: {integrity: sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -9958,9 +9992,6 @@ packages: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -10066,29 +10097,23 @@ packages: resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==} engines: {node: '>=0.8'} - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - stacktrace-parser@0.1.11: resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==} engines: {node: '>=6'} - state-local@1.0.7: - resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} - statuses@2.0.2: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} - std-env@4.1.0: - resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + std-env@4.3.0: + resolution: {integrity: sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag==} stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} - storybook@10.5.6: - resolution: {integrity: sha512-VhYwqxPySa24CVXKoWD6gCZXx9//DTmo43YpusGuAoHDYj5Osjt8wuBRQVeGoaLUWnHiPWv8S+GYHrJEaBM6Rg==} + storybook@10.6.1: + resolution: {integrity: sha512-NeEmukMWPA5OqHizUkQtxCIhGt7MUZLPY4FFgpC0LNiipjrac/oKpH0TxI+9Zc+vI5+IoN+NiskOmBP7gtYfmA==} hasBin: true peerDependencies: '@types/react': '*' @@ -10102,10 +10127,6 @@ packages: vite-plus: optional: true - streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} - streamx@2.26.0: resolution: {integrity: sha512-VvNG1K72Po/xwJzxZFnZ++Tbrv4lwSptsbkFuzXCJAYZvCK5nnxsvXU6ajqkv7chyiI1Y0YXq2Jh8Iy8Y7NF/A==} @@ -10237,9 +10258,6 @@ packages: engines: {node: '>=16'} hasBin: true - swagger-ui-dist@5.32.6: - resolution: {integrity: sha512-75ttZNaYCLoFPnozPZcTUU6mS3wKT8l7WLjU5zJSHFeJa23i5vtnze6IiCl4jDMPeQTXVXIgovq4M11NNfQvSA==} - synckit@0.11.13: resolution: {integrity: sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==} engines: {node: ^14.18.0 || >=16.0.0} @@ -10283,13 +10301,18 @@ packages: tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinybench@6.2.0: + resolution: {integrity: sha512-78U2TlB2CnVenajOFzf3BKSm0J6oz5L0NV7g32LCPccvYc0lbWvys4d3uUUCS2B1N8PAf2+aekR8i1KbC3HO7Q==} + engines: {node: '>=20.0.0'} tinyexec@1.2.4: resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} engines: {node: '>=18'} + tinyexec@1.3.1: + resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==} + engines: {node: '>=18'} + tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} @@ -10298,8 +10321,8 @@ packages: resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} engines: {node: '>=14.0.0'} - tinyrainbow@3.1.0: - resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + tinyrainbow@3.1.1: + resolution: {integrity: sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==} engines: {node: '>=14.0.0'} tinyspy@4.0.4: @@ -10412,10 +10435,6 @@ packages: resolution: {integrity: sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==} engines: {node: '>=20'} - type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} - type-is@2.1.0: resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} engines: {node: '>= 18'} @@ -10436,15 +10455,15 @@ packages: resolution: {integrity: sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==} engines: {node: '>= 0.4'} - typedoc-plugin-markdown@4.4.2: - resolution: {integrity: sha512-kJVkU2Wd+AXQpyL6DlYXXRrfNrHrEIUgiABWH8Z+2Lz5Sq6an4dQ/hfvP75bbokjNDUskOdFlEEm/0fSVyC7eg==} + typedoc-plugin-markdown@4.13.1: + resolution: {integrity: sha512-d3jchJ4CyIrV9w9uozTSkfMYG8IEM1RvvGOaybJ/3rRporzoX7p0lprffo95GOGUviQqP0phjHJE3bY8PQbilA==} engines: {node: '>= 18'} peerDependencies: - typedoc: 0.27.x + typedoc: 0.28.x - typedoc@0.27.9: - resolution: {integrity: sha512-/z585740YHURLl9DN2jCWe6OW7zKYm6VoQ93H0sxZ1cwHQEQrUn5BJrEnkWhfzUdyO+BLGjnKUZ9iz9hKloFDw==} - engines: {node: '>= 18'} + typedoc@0.28.20: + resolution: {integrity: sha512-uSKqkh8Cr48vllnEy+jdaAgOeR6Y+QCBW7usgUsKj7gJEfR7stw9U/fE49LBnj2tPRKPY0c0EBJSWe9Appmplg==} + engines: {node: '>= 18', pnpm: '>= 10'} hasBin: true peerDependencies: typescript: 6.0.x @@ -10495,9 +10514,6 @@ packages: uncrypto@0.1.3: resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici-types@7.24.6: resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} @@ -10719,8 +10735,8 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - victory-vendor@36.9.2: - resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} + victory-vendor@37.3.6: + resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} vite-plugin-compression@0.5.1: resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==} @@ -10767,15 +10783,16 @@ packages: yaml: optional: true - vite@7.3.6: - resolution: {integrity: sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==} + vite@8.3.1: + resolution: {integrity: sha512-/bvH9E9tmCXRGp2uXY3WbOldqpTwFkbha/8ANaEQ6VkxhH60KyqLwgZq6lG2y+4uT55x9+9eUHMpQ7uGnOCKjA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.7.1 + esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' less: ^4.0.0 - lightningcss: ^1.21.0 sass: ^1.70.0 sass-embedded: ^1.70.0 stylus: '>=0.54.8' @@ -10786,12 +10803,14 @@ packages: peerDependenciesMeta: '@types/node': optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true jiti: optional: true less: optional: true - lightningcss: - optional: true sass: optional: true sass-embedded: @@ -10815,23 +10834,23 @@ packages: vite: optional: true - vitest@4.1.11: - resolution: {integrity: sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==} - engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + vitest@5.0.2: + resolution: {integrity: sha512-7MQrx9pDv5aHiUcovIb/70Ys3tgtkUVgCtledvKdCmEO+/1Dicq5ZqoSxOW034m03oqC+oHOKui2dM6qtMLoJg==} + engines: {node: ^22.12.0 || ^24.0.0 || >=26.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 - '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.11 - '@vitest/browser-preview': 4.1.11 - '@vitest/browser-webdriverio': 4.1.11 - '@vitest/coverage-istanbul': 4.1.11 - '@vitest/coverage-v8': 4.1.11 - '@vitest/ui': 4.1.11 + '@types/node': ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 5.0.2 + '@vitest/browser-preview': 5.0.2 + '@vitest/browser-webdriverio': ^5.0.0-beta.5 || >=5.0.0 + '@vitest/coverage-istanbul': 5.0.2 + '@vitest/coverage-v8': 5.0.2 + '@vitest/ui': 5.0.2 happy-dom: '*' jsdom: '*' - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + vite: ^6.4.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -11008,9 +11027,9 @@ packages: engines: {node: '>= 8'} hasBin: true - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} + why-is-node-running@3.2.2: + resolution: {integrity: sha512-NKUzAelcoCXhXL4dJzKIwXeR8iEVqsA0Lq6Vnd0UXvgaKbzVo4ZTHROF2Jidrv+SgxOQ03fMinnNhzZATxOD3A==} + engines: {node: '>=20.11'} hasBin: true widest-line@5.0.0: @@ -11261,12 +11280,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@astrojs/mdx@4.3.14(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0))': + '@astrojs/mdx@4.3.14(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0))': dependencies: '@astrojs/markdown-remark': 6.3.11 '@mdx-js/mdx': 3.1.1 acorn: 8.16.0 - astro: 5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0) + astro: 5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0) es-module-lexer: 1.7.0 estree-util-visit: 2.0.0 hast-util-to-html: 9.0.5 @@ -11289,22 +11308,22 @@ snapshots: sitemap: 9.0.1 zod: 4.4.3 - '@astrojs/starlight-tailwind@4.0.2(@astrojs/starlight@0.34.8(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0)))(tailwindcss@4.3.3)': + '@astrojs/starlight-tailwind@4.0.2(@astrojs/starlight@0.34.8(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0)))(tailwindcss@4.3.3)': dependencies: - '@astrojs/starlight': 0.34.8(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0)) + '@astrojs/starlight': 0.34.8(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0)) tailwindcss: 4.3.3 - '@astrojs/starlight@0.34.8(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0))': + '@astrojs/starlight@0.34.8(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0))': dependencies: '@astrojs/markdown-remark': 6.3.11 - '@astrojs/mdx': 4.3.14(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0)) + '@astrojs/mdx': 4.3.14(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0)) '@astrojs/sitemap': 3.7.4 '@pagefind/default-ui': 1.5.2 '@types/hast': 3.0.4 '@types/js-yaml': 4.0.9 '@types/mdast': 4.0.4 - astro: 5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0) - astro-expressive-code: 0.41.7(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0)) + astro: 5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0) + astro-expressive-code: 0.41.7(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0)) bcp-47: 2.1.0 hast-util-from-html: 2.0.3 hast-util-select: 6.0.4 @@ -11528,11 +11547,11 @@ snapshots: '@babel/core@7.29.7': dependencies: '@babel/code-frame': 7.29.7 - '@babel/generator': 7.29.7 + '@babel/generator': 7.29.8 '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) '@babel/helpers': 7.29.7 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.9 '@babel/template': 7.29.7 '@babel/traverse': 7.29.7 '@babel/types': 7.29.8 @@ -11545,14 +11564,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.29.7': - dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.8 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - '@babel/generator@7.29.8': dependencies: '@babel/parser': 7.29.9 @@ -11598,10 +11609,6 @@ snapshots: '@babel/template': 7.29.7 '@babel/types': 7.29.8 - '@babel/parser@7.29.7': - dependencies: - '@babel/types': 7.29.7 - '@babel/parser@7.29.9': dependencies: '@babel/types': 7.29.8 @@ -11611,26 +11618,21 @@ snapshots: '@babel/template@7.29.7': dependencies: '@babel/code-frame': 7.29.7 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.9 '@babel/types': 7.29.8 '@babel/traverse@7.29.7': dependencies: '@babel/code-frame': 7.29.7 - '@babel/generator': 7.29.7 + '@babel/generator': 7.29.8 '@babel/helper-globals': 7.29.7 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.9 '@babel/template': 7.29.7 '@babel/types': 7.29.8 debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.29.7': - dependencies: - '@babel/helper-string-parser': 7.29.7 - '@babel/helper-validator-identifier': 7.29.7 - '@babel/types@7.29.8': dependencies: '@babel/helper-string-parser': 7.29.7 @@ -11676,15 +11678,9 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} - '@blazediff/core@1.9.1': - optional: true - '@borewit/text-codec@0.2.2': {} - '@cap.js/server@2.0.0': - dependencies: - '@types/node': 22.19.21 - typescript: 6.0.3 + '@cap.js/server@4.0.5': {} '@cap.js/widget@0.1.58': {} @@ -11692,16 +11688,16 @@ snapshots: dependencies: fontkitten: 1.0.3 - '@casl/ability@6.8.1': + '@casl/ability@7.0.1': dependencies: - '@ucast/mongo2js': 1.4.1 + '@ucast/mongo2js': 2.0.0 - '@casl/prisma@1.6.2(@casl/ability@6.8.1)(@prisma/client@6.19.3(prisma@6.19.3(typescript@6.0.3))(typescript@6.0.3))': + '@casl/prisma@2.0.2(@casl/ability@7.0.1)(@prisma/client@6.19.3(prisma@6.19.3(typescript@6.0.3))(typescript@6.0.3))': dependencies: - '@casl/ability': 6.8.1 + '@casl/ability': 7.0.1 '@prisma/client': 6.19.3(prisma@6.19.3(typescript@6.0.3))(typescript@6.0.3) - '@ucast/core': 1.10.2 - '@ucast/js': 3.1.0 + '@ucast/core': 2.0.0 + '@ucast/js': 4.0.1 '@commander-js/extra-typings@13.1.0(commander@13.1.0)': dependencies: @@ -11748,7 +11744,7 @@ snapshots: '@commitlint/is-ignored@21.2.3': dependencies: '@commitlint/types': 21.2.3 - semver: 7.8.1 + semver: 7.8.5 '@commitlint/lint@21.2.3': dependencies: @@ -11820,7 +11816,7 @@ snapshots: dependencies: '@simple-libs/child-process-utils': 2.0.0 '@simple-libs/stream-utils': 2.0.0 - semver: 7.8.1 + semver: 7.8.5 optionalDependencies: conventional-commits-parser: 7.1.2 @@ -11891,15 +11887,14 @@ snapshots: type-fest: 4.41.0 zod: link:vendor/zod@3.x - '@douglasneuroinformatics/libnest@9.0.0(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6)(@nestjs/platform-fastify@11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6))(@nestjs/testing@11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6)(@nestjs/platform-express@11.2.6))(@prisma/client@6.19.3(prisma@6.19.3(typescript@6.0.3))(typescript@6.0.3))(@swc/types@0.1.28)(fastify@5.12.5)(neverthrow@8.2.0)(reflect-metadata@0.1.14)(rollup@4.61.1)(rxjs@7.8.2)(typescript@6.0.3)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0))(vitest@4.1.11)(zod@vendor+zod@3.x)': + '@douglasneuroinformatics/libnest@10.0.0(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-fastify@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2)))(@nestjs/testing@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2)))(@prisma/client@6.19.3(prisma@6.19.3(typescript@6.0.3))(typescript@6.0.3))(@swc/types@0.1.28)(fastify@5.12.5)(neverthrow@8.2.0)(reflect-metadata@0.2.2)(rollup@4.61.1)(rxjs@7.8.2)(typescript@6.0.3)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0))(vitest@5.0.2)(zod@vendor+zod@3.x)': dependencies: '@douglasneuroinformatics/libjs': 3.2.1(neverthrow@8.2.0)(zod@vendor+zod@3.x) - '@nestjs/common': 11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2) - '@nestjs/core': 11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/platform-express@11.2.6)(reflect-metadata@0.1.14)(rxjs@7.8.2) - '@nestjs/platform-fastify': 11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6) - '@nestjs/swagger': 11.4.4(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6)(reflect-metadata@0.1.14) - '@nestjs/testing': 11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6)(@nestjs/platform-express@11.2.6) - '@nestjs/throttler': 6.7.1(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6)(reflect-metadata@0.1.14) + '@nestjs/common': 12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-fastify': 12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2)) + '@nestjs/testing': 12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2)) + '@nestjs/throttler': 6.7.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2) '@prisma/client': 6.19.3(prisma@6.19.3(typescript@6.0.3))(typescript@6.0.3) '@prisma/engines': 6.19.3 '@prisma/get-platform': 6.19.3 @@ -11910,27 +11905,24 @@ snapshots: '@types/supertest': 6.0.3 chalk: 5.6.2 commander: 14.0.3 - es-module-lexer: 2.1.0 + es-module-lexer: 2.3.2 esbuild: 0.27.7 fastify: 5.12.5 neverthrow: 8.2.0 nodemailer: 7.0.13 - reflect-metadata: 0.1.14 + reflect-metadata: 0.2.2 rxjs: 7.8.2 serialize-error: 13.0.1 supertest: 7.2.2 ts-morph: 27.0.2 type-fest: 5.7.0 unplugin-swc: 1.5.9(@swc/core@1.16.2(@swc/helpers@0.5.23))(rollup@4.61.1) - vitest: 4.1.11(@types/node@24.19.0)(@vitest/coverage-v8@4.1.11)(happy-dom@20.11.15)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + vitest: 5.0.2(@types/node@24.19.0)(@vitest/coverage-v8@5.0.2)(happy-dom@20.11.15)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) zod: link:vendor/zod@3.x optionalDependencies: - vite: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + vite: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) transitivePeerDependencies: - - '@fastify/static' - '@swc/types' - - class-transformer - - class-validator - rollup - supports-color - typescript @@ -12015,7 +12007,7 @@ snapshots: class-variance-authority: 0.7.1 clsx: 2.1.1 lodash-es: 4.18.1 - lucide-react: 1.17.0(react@19.1.0) + lucide-react: 1.49.0(react@19.1.0) motion: 11.18.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) @@ -12072,7 +12064,7 @@ snapshots: class-variance-authority: 0.7.1 clsx: 2.1.1 lodash-es: 4.18.1 - lucide-react: 1.17.0(react@vendor+react@19.x) + lucide-react: 1.49.0(react@vendor+react@19.x) motion: 11.18.2(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) react: link:vendor/react@19.x react-dom: link:vendor/react-dom@19.x @@ -12097,7 +12089,7 @@ snapshots: - neverthrow - use-sync-external-store - '@douglasneuroinformatics/prettier-config@0.3.0(husky@9.1.7)(prettier-plugin-astro@0.14.1)(prettier-plugin-tailwindcss@0.8.1(prettier-plugin-astro@0.14.1)(prettier@3.9.9))(prettier@3.9.9)': + '@douglasneuroinformatics/prettier-config@0.4.0(husky@9.1.7)(prettier-plugin-astro@0.14.1)(prettier-plugin-tailwindcss@0.8.1(prettier-plugin-astro@0.14.1)(prettier@3.9.9))(prettier@3.9.9)': dependencies: prettier: 3.9.9 optionalDependencies: @@ -12132,9 +12124,9 @@ snapshots: '@emmetio/stream-reader@2.2.0': {} - '@emnapi/core@1.10.0': + '@emnapi/core@1.11.0': dependencies: - '@emnapi/wasi-threads': 1.2.1 + '@emnapi/wasi-threads': 1.2.2 tslib: 2.8.1 optional: true @@ -12155,6 +12147,11 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/runtime@1.11.0': + dependencies: + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.11.2': dependencies: tslib: 2.8.1 @@ -12490,7 +12487,7 @@ snapshots: dependencies: '@expressive-code/core': 0.41.7 - '@faker-js/faker@10.2.0': {} + '@faker-js/faker@10.6.0': {} '@fastify/ajv-compiler@4.0.5': dependencies: @@ -12509,10 +12506,10 @@ snapshots: dependencies: fast-json-stringify: 6.4.0 - '@fastify/formbody@8.0.2': + '@fastify/formbody@9.0.0': dependencies: fast-querystring: 1.1.2 - fastify-plugin: 5.1.0 + fastify-plugin: 6.0.0 '@fastify/forwarded@3.0.1': {} @@ -12556,10 +12553,12 @@ snapshots: '@floating-ui/utils@0.2.11': {} - '@gerrit0/mini-shiki@1.27.2': + '@gerrit0/mini-shiki@3.23.0': dependencies: - '@shikijs/engine-oniguruma': 1.29.2 - '@shikijs/types': 1.29.2 + '@shikijs/engine-oniguruma': 3.23.0 + '@shikijs/langs': 3.23.0 + '@shikijs/themes': 3.23.0 + '@shikijs/types': 3.23.0 '@shikijs/vscode-textmate': 10.0.2 '@heroicons/react@2.2.0(react@vendor+react@19.x)': @@ -12708,17 +12707,17 @@ snapshots: '@isaacs/cliui@9.0.0': {} - '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0(typescript@6.0.3)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0(typescript@6.0.3)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0))': dependencies: glob: 13.0.6 react-docgen-typescript: 2.4.0(typescript@6.0.3) - vite: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + vite: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) optionalDependencies: typescript: 6.0.3 '@jridgewell/gen-mapping@0.3.13': dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.6.0 '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/remapping@2.3.5': @@ -12730,10 +12729,12 @@ snapshots: '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/sourcemap-codec@1.6.0': {} + '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.6.0 '@jspsych/plugin-html-button-response@1.2.0(jspsych@7.3.4)': dependencies: @@ -12887,21 +12888,8 @@ snapshots: jju: 1.4.0 resolve: 1.22.12 - '@microsoft/tsdoc@0.16.0': {} - '@microsoft/tsdoc@0.17.0': {} - '@monaco-editor/loader@1.7.0': - dependencies: - state-local: 1.0.7 - - '@monaco-editor/react@4.7.0(monaco-editor@0.54.0)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)': - dependencies: - '@monaco-editor/loader': 1.7.0 - monaco-editor: 0.54.0 - react: link:vendor/react@19.x - react-dom: link:vendor/react-dom@19.x - '@mongodb-js/saslprep@1.4.11': dependencies: sparse-bitfield: 3.0.3 @@ -12924,18 +12912,11 @@ snapshots: '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4': optional: true - '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.2 - optional: true - - '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + '@napi-rs/wasm-runtime@1.2.4(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)': dependencies: - '@emnapi/core': 1.9.2 - '@emnapi/runtime': 1.9.2 - '@tybys/wasm-util': 0.10.2 + '@emnapi/core': 1.11.0 + '@emnapi/runtime': 1.11.0 + '@tybys/wasm-util': 0.10.4 optional: true '@napi-rs/wasm-runtime@1.2.4(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': @@ -12945,72 +12926,61 @@ snapshots: '@tybys/wasm-util': 0.10.4 optional: true - '@nestjs/axios@12.0.1(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(axios@1.20.0)(rxjs@7.8.2)': + '@napi-rs/wasm-runtime@1.2.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + dependencies: + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.9.2 + '@tybys/wasm-util': 0.10.4 + optional: true + + '@nestjs/axios@12.0.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.20.0)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2) + '@nestjs/common': 12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2) axios: 1.20.0 rxjs: 7.8.2 - '@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2)': + '@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - file-type: 21.3.4 + '@standard-schema/spec': 1.1.0 + file-type: 22.1.1 iterare: 1.2.1 load-esm: 1.0.3 - reflect-metadata: 0.1.14 + reflect-metadata: 0.2.2 rxjs: 7.8.2 tslib: 2.8.1 uid: 2.0.2 transitivePeerDependencies: - supports-color - '@nestjs/core@11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/platform-express@11.2.6)(reflect-metadata@0.1.14)(rxjs@7.8.2)': + '@nestjs/core@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2) + '@nestjs/common': 12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2) fast-safe-stringify: 2.1.1 iterare: 1.2.1 path-to-regexp: 8.4.2 - reflect-metadata: 0.1.14 + reflect-metadata: 0.2.2 rxjs: 7.8.2 tslib: 2.8.1 uid: 2.0.2 - optionalDependencies: - '@nestjs/platform-express': 11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6) - '@nestjs/jwt@12.0.2(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))': + '@nestjs/jwt@12.0.2(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))': dependencies: - '@nestjs/common': 11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2) + '@nestjs/common': 12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2) '@types/jsonwebtoken': 9.0.10 jsonwebtoken: 9.0.3 - '@nestjs/mapped-types@2.1.1(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)': - dependencies: - '@nestjs/common': 11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2) - reflect-metadata: 0.1.14 - - '@nestjs/passport@12.0.0(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(passport@0.7.0)': + '@nestjs/passport@12.0.0(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0)': dependencies: - '@nestjs/common': 11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2) + '@nestjs/common': 12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2) passport: 0.7.0 - '@nestjs/platform-express@11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6)': - dependencies: - '@nestjs/common': 11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2) - '@nestjs/core': 11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/platform-express@11.2.6)(reflect-metadata@0.1.14)(rxjs@7.8.2) - cors: 2.8.6 - express: 5.2.1 - multer: 2.4.0 - path-to-regexp: 8.4.2 - tslib: 2.8.1 - transitivePeerDependencies: - - supports-color - - '@nestjs/platform-fastify@11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6)': + '@nestjs/platform-fastify@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2))': dependencies: '@fastify/cors': 11.3.0 - '@fastify/formbody': 8.0.2 + '@fastify/formbody': 9.0.0 '@fastify/middie': 9.3.4 - '@nestjs/common': 11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2) - '@nestjs/core': 11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/platform-express@11.2.6)(reflect-metadata@0.1.14)(rxjs@7.8.2) + '@nestjs/common': 12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2) fast-querystring: 1.1.2 fastify: 5.12.5 find-my-way: 9.7.0 @@ -13018,31 +12988,17 @@ snapshots: path-to-regexp: 8.4.2 tslib: 2.8.1 - '@nestjs/swagger@11.4.4(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6)(reflect-metadata@0.1.14)': + '@nestjs/testing@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2))': dependencies: - '@microsoft/tsdoc': 0.16.0 - '@nestjs/common': 11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2) - '@nestjs/core': 11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/platform-express@11.2.6)(reflect-metadata@0.1.14)(rxjs@7.8.2) - '@nestjs/mapped-types': 2.1.1(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14) - js-yaml: 4.1.1 - lodash: 4.18.1 - path-to-regexp: 8.4.2 - reflect-metadata: 0.1.14 - swagger-ui-dist: 5.32.6 - - '@nestjs/testing@11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6)(@nestjs/platform-express@11.2.6)': - dependencies: - '@nestjs/common': 11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2) - '@nestjs/core': 11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/platform-express@11.2.6)(reflect-metadata@0.1.14)(rxjs@7.8.2) + '@nestjs/common': 12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2) tslib: 2.8.1 - optionalDependencies: - '@nestjs/platform-express': 11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6) - '@nestjs/throttler@6.7.1(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.2.6)(reflect-metadata@0.1.14)': + '@nestjs/throttler@6.7.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)': dependencies: - '@nestjs/common': 11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2) - '@nestjs/core': 11.2.6(@nestjs/common@11.2.6(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/platform-express@11.2.6)(reflect-metadata@0.1.14)(rxjs@7.8.2) - reflect-metadata: 0.1.14 + '@nestjs/common': 12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 12.1.1(@nestjs/common@12.1.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2) + reflect-metadata: 0.2.2 '@noble/hashes@1.8.0': {} @@ -13215,7 +13171,7 @@ snapshots: dependencies: '@emnapi/core': 1.9.2 '@emnapi/runtime': 1.9.2 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + '@napi-rs/wasm-runtime': 1.2.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) optional: true '@oxc-parser/binding-win32-arm64-msvc@0.127.0': @@ -13240,107 +13196,109 @@ snapshots: '@oxc-project/types@0.150.0': {} - '@oxc-resolver/binding-android-arm-eabi@11.20.0': + '@oxc-project/types@0.152.0': {} + + '@oxc-resolver/binding-android-arm-eabi@11.21.2': optional: true '@oxc-resolver/binding-android-arm-eabi@11.24.2': optional: true - '@oxc-resolver/binding-android-arm64@11.20.0': + '@oxc-resolver/binding-android-arm64@11.21.2': optional: true '@oxc-resolver/binding-android-arm64@11.24.2': optional: true - '@oxc-resolver/binding-darwin-arm64@11.20.0': + '@oxc-resolver/binding-darwin-arm64@11.21.2': optional: true '@oxc-resolver/binding-darwin-arm64@11.24.2': optional: true - '@oxc-resolver/binding-darwin-x64@11.20.0': + '@oxc-resolver/binding-darwin-x64@11.21.2': optional: true '@oxc-resolver/binding-darwin-x64@11.24.2': optional: true - '@oxc-resolver/binding-freebsd-x64@11.20.0': + '@oxc-resolver/binding-freebsd-x64@11.21.2': optional: true '@oxc-resolver/binding-freebsd-x64@11.24.2': optional: true - '@oxc-resolver/binding-linux-arm-gnueabihf@11.20.0': + '@oxc-resolver/binding-linux-arm-gnueabihf@11.21.2': optional: true '@oxc-resolver/binding-linux-arm-gnueabihf@11.24.2': optional: true - '@oxc-resolver/binding-linux-arm-musleabihf@11.20.0': + '@oxc-resolver/binding-linux-arm-musleabihf@11.21.2': optional: true '@oxc-resolver/binding-linux-arm-musleabihf@11.24.2': optional: true - '@oxc-resolver/binding-linux-arm64-gnu@11.20.0': + '@oxc-resolver/binding-linux-arm64-gnu@11.21.2': optional: true '@oxc-resolver/binding-linux-arm64-gnu@11.24.2': optional: true - '@oxc-resolver/binding-linux-arm64-musl@11.20.0': + '@oxc-resolver/binding-linux-arm64-musl@11.21.2': optional: true '@oxc-resolver/binding-linux-arm64-musl@11.24.2': optional: true - '@oxc-resolver/binding-linux-ppc64-gnu@11.20.0': + '@oxc-resolver/binding-linux-ppc64-gnu@11.21.2': optional: true '@oxc-resolver/binding-linux-ppc64-gnu@11.24.2': optional: true - '@oxc-resolver/binding-linux-riscv64-gnu@11.20.0': + '@oxc-resolver/binding-linux-riscv64-gnu@11.21.2': optional: true '@oxc-resolver/binding-linux-riscv64-gnu@11.24.2': optional: true - '@oxc-resolver/binding-linux-riscv64-musl@11.20.0': + '@oxc-resolver/binding-linux-riscv64-musl@11.21.2': optional: true '@oxc-resolver/binding-linux-riscv64-musl@11.24.2': optional: true - '@oxc-resolver/binding-linux-s390x-gnu@11.20.0': + '@oxc-resolver/binding-linux-s390x-gnu@11.21.2': optional: true '@oxc-resolver/binding-linux-s390x-gnu@11.24.2': optional: true - '@oxc-resolver/binding-linux-x64-gnu@11.20.0': + '@oxc-resolver/binding-linux-x64-gnu@11.21.2': optional: true '@oxc-resolver/binding-linux-x64-gnu@11.24.2': optional: true - '@oxc-resolver/binding-linux-x64-musl@11.20.0': + '@oxc-resolver/binding-linux-x64-musl@11.21.2': optional: true '@oxc-resolver/binding-linux-x64-musl@11.24.2': optional: true - '@oxc-resolver/binding-openharmony-arm64@11.20.0': + '@oxc-resolver/binding-openharmony-arm64@11.21.2': optional: true '@oxc-resolver/binding-openharmony-arm64@11.24.2': optional: true - '@oxc-resolver/binding-wasm32-wasi@11.20.0': + '@oxc-resolver/binding-wasm32-wasi@11.21.2': dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@emnapi/core': 1.11.0 + '@emnapi/runtime': 1.11.0 + '@napi-rs/wasm-runtime': 1.2.4(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0) optional: true '@oxc-resolver/binding-wasm32-wasi@11.24.2': @@ -13350,13 +13308,13 @@ snapshots: '@napi-rs/wasm-runtime': 1.2.4(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) optional: true - '@oxc-resolver/binding-win32-arm64-msvc@11.20.0': + '@oxc-resolver/binding-win32-arm64-msvc@11.21.2': optional: true '@oxc-resolver/binding-win32-arm64-msvc@11.24.2': optional: true - '@oxc-resolver/binding-win32-x64-msvc@11.20.0': + '@oxc-resolver/binding-win32-x64-msvc@11.21.2': optional: true '@oxc-resolver/binding-win32-x64-msvc@11.24.2': @@ -14594,13 +14552,70 @@ snapshots: '@radix-ui/rect@1.1.3': {} + '@reduxjs/toolkit@2.13.0(react-redux@9.3.0(react@vendor+react@19.x)(redux@5.0.1))(react@vendor+react@19.x)': + dependencies: + '@standard-schema/spec': 1.1.0 + '@standard-schema/utils': 0.3.0 + immer: 11.1.18 + redux: 5.0.1 + redux-thunk: 3.1.0(redux@5.0.1) + reselect: 5.2.0 + optionalDependencies: + react: link:vendor/react@19.x + react-redux: 9.3.0(react@vendor+react@19.x)(redux@5.0.1) + + '@rolldown/binding-android-arm-eabi@1.2.12': + optional: true + + '@rolldown/binding-android-arm64@1.2.12': + optional: true + + '@rolldown/binding-darwin-arm64@1.2.12': + optional: true + + '@rolldown/binding-darwin-x64@1.2.12': + optional: true + + '@rolldown/binding-freebsd-x64@1.2.12': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.2.12': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.2.12': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.2.12': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.2.12': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.2.12': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.2.12': + optional: true + + '@rolldown/binding-linux-x64-musl@1.2.12': + optional: true + + '@rolldown/binding-openharmony-arm64@1.2.12': + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.2.12': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.2.12': + optional: true + '@rolldown/pluginutils@1.0.1': {} '@rollup/pluginutils@5.4.0(rollup@4.61.1)': dependencies: '@types/estree': 1.0.9 estree-walker: 2.0.2 - picomatch: 4.0.4 + picomatch: 4.0.7 optionalDependencies: rollup: 4.61.1 @@ -14720,8 +14735,6 @@ snapshots: transitivePeerDependencies: - '@types/node' - '@scarf/scarf@1.4.0': {} - '@shikijs/core@3.23.0': dependencies: '@shikijs/types': 3.23.0 @@ -14735,11 +14748,6 @@ snapshots: '@shikijs/vscode-textmate': 10.0.2 oniguruma-to-es: 4.3.6 - '@shikijs/engine-oniguruma@1.29.2': - dependencies: - '@shikijs/types': 1.29.2 - '@shikijs/vscode-textmate': 10.0.2 - '@shikijs/engine-oniguruma@3.23.0': dependencies: '@shikijs/types': 3.23.0 @@ -14753,11 +14761,6 @@ snapshots: dependencies: '@shikijs/types': 3.23.0 - '@shikijs/types@1.29.2': - dependencies: - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - '@shikijs/types@3.23.0': dependencies: '@shikijs/vscode-textmate': 10.0.2 @@ -14874,67 +14877,37 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@storybook/addon-docs@10.5.6(esbuild@0.28.2)(rollup@4.61.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0))': + '@standard-schema/utils@0.3.0': {} + + '@storybook/addon-docs@10.6.1(storybook@10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))': dependencies: '@mdx-js/react': 3.1.1(react@18.3.1) - '@storybook/csf-plugin': 10.5.6(esbuild@0.28.2)(rollup@4.61.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) '@storybook/icons': 2.0.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/react-dom-shim': 10.5.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)) + '@storybook/react-dom-shim': 10.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - storybook: 10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + storybook: 10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) ts-dedent: 2.2.0 + unplugin: 2.3.11 transitivePeerDependencies: - '@types/react-dom' - - esbuild - - rollup - - vite - - webpack - '@storybook/addon-themes@10.5.6(storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))': + '@storybook/addon-themes@10.6.1(storybook@10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))': dependencies: - storybook: 10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + storybook: 10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) ts-dedent: 2.2.0 - '@storybook/builder-vite@10.5.6(esbuild@0.28.2)(rollup@4.61.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0))': + '@storybook/builder-vite@10.6.1(storybook@10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0))': dependencies: - '@storybook/csf-plugin': 10.5.6(esbuild@0.28.2)(rollup@4.61.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) - storybook: 10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + storybook: 10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) ts-dedent: 2.2.0 - vite: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) - transitivePeerDependencies: - - esbuild - - rollup - - webpack + vite: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) - '@storybook/builder-vite@10.5.6(esbuild@0.28.2)(rollup@4.61.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0))': + '@storybook/builder-vite@10.6.1(storybook@10.6.1(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0))': dependencies: - '@storybook/csf-plugin': 10.5.6(esbuild@0.28.2)(rollup@4.61.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) - storybook: 10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) + storybook: 10.6.1(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) ts-dedent: 2.2.0 - vite: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) - transitivePeerDependencies: - - esbuild - - rollup - - webpack - - '@storybook/csf-plugin@10.5.6(esbuild@0.28.2)(rollup@4.61.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0))': - dependencies: - storybook: 10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - unplugin: 2.3.11 - optionalDependencies: - esbuild: 0.28.2 - rollup: 4.61.1 - vite: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) - - '@storybook/csf-plugin@10.5.6(esbuild@0.28.2)(rollup@4.61.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0))': - dependencies: - storybook: 10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) - unplugin: 2.3.11 - optionalDependencies: - esbuild: 0.28.2 - rollup: 4.61.1 - vite: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + vite: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) '@storybook/global@5.0.0': {} @@ -14953,97 +14926,93 @@ snapshots: react: link:vendor/react@19.x react-dom: link:vendor/react-dom@19.x - '@storybook/react-dom-shim@10.5.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))': + '@storybook/react-dom-shim@10.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))': dependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - storybook: 10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + storybook: 10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@storybook/react-dom-shim@10.5.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))': + '@storybook/react-dom-shim@10.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))': dependencies: react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - storybook: 10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + storybook: 10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@storybook/react-dom-shim@10.5.6(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)(storybook@10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))': + '@storybook/react-dom-shim@10.6.1(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)(storybook@10.6.1(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))': dependencies: react: link:vendor/react@19.x react-dom: link:vendor/react-dom@19.x - storybook: 10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) + storybook: 10.6.1(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) - '@storybook/react-vite@10.5.6(esbuild@0.28.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(rollup@4.61.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(typescript@6.0.3)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0))': + '@storybook/react-vite@10.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(rollup@4.61.1)(storybook@10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(typescript@6.0.3)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@6.0.3)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@6.0.3)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) '@rollup/pluginutils': 5.4.0(rollup@4.61.1) - '@storybook/builder-vite': 10.5.6(esbuild@0.28.2)(rollup@4.61.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) - '@storybook/react': 10.5.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(typescript@6.0.3) + '@storybook/builder-vite': 10.6.1(storybook@10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) + '@storybook/react': 10.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(typescript@6.0.3) empathic: 2.0.1 - magic-string: 0.30.21 + magic-string: 1.4.2 react: 19.1.0 react-docgen: 8.0.3 react-dom: 19.1.0(react@19.1.0) resolve: 1.22.12 - storybook: 10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + storybook: 10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) tsconfig-paths: 4.2.0 - vite: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + vite: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) optionalDependencies: typescript: 6.0.3 transitivePeerDependencies: - '@types/react' - '@types/react-dom' - - esbuild - rollup - supports-color - - webpack - '@storybook/react-vite@10.5.6(esbuild@0.28.2)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)(rollup@4.61.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(typescript@6.0.3)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0))': + '@storybook/react-vite@10.6.1(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)(rollup@4.61.1)(storybook@10.6.1(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(typescript@6.0.3)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@6.0.3)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@6.0.3)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) '@rollup/pluginutils': 5.4.0(rollup@4.61.1) - '@storybook/builder-vite': 10.5.6(esbuild@0.28.2)(rollup@4.61.1)(storybook@10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) - '@storybook/react': 10.5.6(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)(storybook@10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(typescript@6.0.3) + '@storybook/builder-vite': 10.6.1(storybook@10.6.1(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) + '@storybook/react': 10.6.1(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)(storybook@10.6.1(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(typescript@6.0.3) empathic: 2.0.1 - magic-string: 0.30.21 + magic-string: 1.4.2 react: link:vendor/react@19.x react-docgen: 8.0.3 react-dom: link:vendor/react-dom@19.x resolve: 1.22.12 - storybook: 10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) + storybook: 10.6.1(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) tsconfig-paths: 4.2.0 - vite: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + vite: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) optionalDependencies: typescript: 6.0.3 transitivePeerDependencies: - '@types/react' - '@types/react-dom' - - esbuild - rollup - supports-color - - webpack - '@storybook/react@10.5.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(typescript@6.0.3)': + '@storybook/react@10.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(typescript@6.0.3)': dependencies: '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 10.5.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)) + '@storybook/react-dom-shim': 10.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)) react: 19.1.0 react-docgen: 8.0.3 react-docgen-typescript: 2.4.0(typescript@6.0.3) react-dom: 19.1.0(react@19.1.0) - storybook: 10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + storybook: 10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) optionalDependencies: typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@storybook/react@10.5.6(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)(storybook@10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(typescript@6.0.3)': + '@storybook/react@10.6.1(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)(storybook@10.6.1(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(typescript@6.0.3)': dependencies: '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 10.5.6(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)(storybook@10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)) + '@storybook/react-dom-shim': 10.6.1(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)(storybook@10.6.1(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x)) react: link:vendor/react@19.x react-docgen: 8.0.3 react-docgen-typescript: 2.4.0(typescript@6.0.3) react-dom: link:vendor/react-dom@19.x - storybook: 10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) + storybook: 10.6.1(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) optionalDependencies: typescript: 6.0.3 transitivePeerDependencies: @@ -15063,7 +15032,7 @@ snapshots: colorette: 2.0.20 debug: 4.4.3 fast-json-stable-stringify: 2.1.0 - oxc-resolver: 11.20.0 + oxc-resolver: 11.24.2 pirates: 4.0.7 tslib: 2.8.1 typescript: 6.0.3 @@ -15215,12 +15184,12 @@ snapshots: postcss-selector-parser: 6.0.10 tailwindcss: 4.3.3 - '@tailwindcss/vite@4.3.3(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0))': + '@tailwindcss/vite@4.3.3(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0))': dependencies: '@tailwindcss/node': 4.3.3 '@tailwindcss/oxide': 4.3.3 tailwindcss: 4.3.3 - vite: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + vite: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) '@tanstack/history@1.162.4': {} @@ -15326,7 +15295,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.168.41(@tanstack/react-router@1.170.40(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(esbuild@0.28.2)(rollup@4.61.1)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0))': + '@tanstack/router-plugin@1.168.41(@tanstack/react-router@1.170.40(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x))(esbuild@0.28.2)(rolldown@1.2.12)(rollup@4.61.1)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0))': dependencies: '@babel/core': 7.29.7 '@babel/template': 7.29.7 @@ -15335,11 +15304,11 @@ snapshots: '@tanstack/router-generator': 1.167.39 '@tanstack/router-utils': 1.162.3 chokidar: 5.0.0 - unplugin: 3.4.0(esbuild@0.28.2)(rollup@4.61.1)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + unplugin: 3.4.0(esbuild@0.28.2)(rolldown@1.2.12)(rollup@4.61.1)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) zod: 4.6.5 optionalDependencies: '@tanstack/react-router': 1.170.40(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) - vite: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + vite: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -15396,7 +15365,7 @@ snapshots: react: link:vendor/react@19.x react-dom: link:vendor/react-dom@19.x - '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.2)': + '@testing-library/user-event@14.6.7(@testing-library/dom@10.4.2)': dependencies: '@testing-library/dom': 10.4.2 @@ -15433,11 +15402,6 @@ snapshots: '@turbo/windows-arm64@2.11.5': optional: true - '@tybys/wasm-util@0.10.2': - dependencies: - tslib: 2.8.1 - optional: true - '@tybys/wasm-util@0.10.4': dependencies: tslib: 2.8.1 @@ -15449,24 +15413,24 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@types/body-parser@1.19.6': dependencies: @@ -15571,10 +15535,6 @@ snapshots: dependencies: '@types/unist': 3.0.3 - '@types/node@22.19.21': - dependencies: - undici-types: 6.21.0 - '@types/node@24.19.0': dependencies: undici-types: 7.24.6 @@ -15625,7 +15585,7 @@ snapshots: '@types/cookiejar': 2.1.5 '@types/methods': 1.1.4 '@types/node': 24.19.0 - form-data: 4.0.5 + form-data: 4.0.6 '@types/supertest@6.0.3': dependencies: @@ -15639,6 +15599,8 @@ snapshots: '@types/unist@3.0.3': {} + '@types/use-sync-external-store@0.0.6': {} + '@types/webidl-conversions@7.0.3': {} '@types/whatwg-mimetype@3.0.2': {} @@ -15719,7 +15681,7 @@ snapshots: '@typescript-eslint/visitor-keys': 8.60.1 debug: 4.4.3 minimatch: 10.2.5 - semver: 7.8.1 + semver: 7.8.5 tinyglobby: 0.2.17 ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 @@ -15742,65 +15704,43 @@ snapshots: '@typescript-eslint/types': 8.60.1 eslint-visitor-keys: 5.0.1 - '@ucast/core@1.10.2': {} + '@ucast/core@2.0.0': {} - '@ucast/js@3.1.0': + '@ucast/js@4.0.1': dependencies: - '@ucast/core': 1.10.2 + '@ucast/core': 2.0.0 - '@ucast/mongo2js@1.4.1': + '@ucast/mongo2js@2.0.0': dependencies: - '@ucast/core': 1.10.2 - '@ucast/js': 3.1.0 - '@ucast/mongo': 2.4.3 + '@ucast/core': 2.0.0 + '@ucast/js': 4.0.1 + '@ucast/mongo': 3.0.0 - '@ucast/mongo@2.4.3': + '@ucast/mongo@3.0.0': dependencies: - '@ucast/core': 1.10.2 + '@ucast/core': 2.0.0 '@ungap/structured-clone@1.3.1': {} - '@vitejs/plugin-react-swc@4.3.3(@swc/helpers@0.5.23)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0))': + '@vitejs/plugin-react-swc@4.3.3(@swc/helpers@0.5.23)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0))': dependencies: '@rolldown/pluginutils': 1.0.1 '@swc/core': 1.16.2(@swc/helpers@0.5.23) - vite: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + vite: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) transitivePeerDependencies: - '@swc/helpers' - '@vitest/browser@4.1.11(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0))(vitest@4.1.11)': - dependencies: - '@blazediff/core': 1.9.1 - '@vitest/mocker': 4.1.11(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) - '@vitest/utils': 4.1.11 - magic-string: 0.30.21 - pngjs: 7.0.0 - sirv: 3.0.2 - tinyrainbow: 3.1.0 - vitest: 4.1.11(@types/node@24.19.0)(@vitest/coverage-v8@4.1.11)(happy-dom@20.11.15)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) - ws: 8.22.0 - transitivePeerDependencies: - - bufferutil - - msw - - utf-8-validate - - vite - optional: true - - '@vitest/coverage-v8@4.1.11(@vitest/browser@4.1.11)(vitest@4.1.11)': + '@vitest/coverage-v8@5.0.2(vitest@5.0.2)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.1.11 - ast-v8-to-istanbul: 1.0.3 - istanbul-lib-coverage: 3.2.2 - istanbul-lib-report: 3.0.1 - istanbul-reports: 3.2.0 - magicast: 0.5.3 - obug: 2.1.2 - std-env: 4.1.0 - tinyrainbow: 3.1.0 - vitest: 4.1.11(@types/node@24.19.0)(@vitest/coverage-v8@4.1.11)(happy-dom@20.11.15)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) - optionalDependencies: - '@vitest/browser': 4.1.11(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0))(vitest@4.1.11) + '@vitest/istanbul-lib-coverage': 1.0.2 + '@vitest/istanbul-lib-report': 1.0.2 + ast-v8-to-istanbul: 1.0.7 + magicast: 0.5.5 + obug: 2.2.1 + std-env: 4.3.0 + tinyrainbow: 3.1.1 + vitest: 5.0.2(@types/node@24.19.0)(@vitest/coverage-v8@5.0.2)(happy-dom@20.11.15)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) '@vitest/expect@3.2.4': dependencies: @@ -15810,48 +15750,30 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/expect@4.1.11': + '@vitest/istanbul-lib-coverage@1.0.2': {} + + '@vitest/istanbul-lib-report@1.0.2': dependencies: - '@standard-schema/spec': 1.1.0 - '@types/chai': 5.2.3 - '@vitest/spy': 4.1.11 - '@vitest/utils': 4.1.11 - chai: 6.2.2 - tinyrainbow: 3.1.0 + '@vitest/istanbul-lib-coverage': 1.0.2 - '@vitest/mocker@4.1.11(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0))': + '@vitest/mocker@5.0.2(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.11 + '@jridgewell/trace-mapping': 0.3.31 + '@vitest/spy': 5.0.2 estree-walker: 3.0.3 - magic-string: 0.30.21 + magic-string: 1.4.2 optionalDependencies: - vite: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + vite: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) '@vitest/pretty-format@3.2.4': dependencies: tinyrainbow: 2.0.0 - '@vitest/pretty-format@4.1.11': - dependencies: - tinyrainbow: 3.1.0 - - '@vitest/runner@4.1.11': - dependencies: - '@vitest/utils': 4.1.11 - pathe: 2.0.3 - - '@vitest/snapshot@4.1.11': - dependencies: - '@vitest/pretty-format': 4.1.11 - '@vitest/utils': 4.1.11 - magic-string: 0.30.21 - pathe: 2.0.3 - '@vitest/spy@3.2.4': dependencies: tinyspy: 4.0.4 - '@vitest/spy@4.1.11': {} + '@vitest/spy@5.0.2': {} '@vitest/utils@3.2.4': dependencies: @@ -15859,12 +15781,6 @@ snapshots: loupe: 3.2.1 tinyrainbow: 2.0.0 - '@vitest/utils@4.1.11': - dependencies: - '@vitest/pretty-format': 4.1.11 - convert-source-map: 2.0.0 - tinyrainbow: 3.1.0 - '@volar/kit@2.4.28(typescript@6.0.3)': dependencies: '@volar/language-service': 2.4.28 @@ -16002,8 +15918,6 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.2 - append-field@1.0.0: {} - are-docs-informative@0.0.2: {} arg@5.0.2: {} @@ -16105,7 +16019,7 @@ snapshots: dependencies: tslib: 2.8.1 - ast-v8-to-istanbul@1.0.3: + ast-v8-to-istanbul@1.0.7: dependencies: '@jridgewell/trace-mapping': 0.3.31 estree-walker: 3.0.3 @@ -16126,16 +16040,16 @@ snapshots: espree: 10.4.0 fast-glob: 3.3.3 is-glob: 4.0.3 - semver: 7.8.1 + semver: 7.8.5 transitivePeerDependencies: - supports-color - astro-expressive-code@0.41.7(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0)): + astro-expressive-code@0.41.7(astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0)): dependencies: - astro: 5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0) + astro: 5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0) rehype-expressive-code: 0.41.7 - astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0): + astro@5.18.2(@types/node@24.19.0)(idb-keyval@6.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(rollup@4.61.1)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.0): dependencies: '@astrojs/compiler': 2.13.1 '@astrojs/internal-helpers': 0.7.6 @@ -16192,8 +16106,8 @@ snapshots: unist-util-visit: 5.1.0 unstorage: 1.17.5(idb-keyval@6.3.0) vfile: 6.0.3 - vite: 6.4.3(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) - vitefu: 1.1.3(vite@6.4.3(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) + vite: 6.4.3(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)(yaml@2.9.0) + vitefu: 1.1.3(vite@6.4.3(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)(yaml@2.9.0)) xxhash-wasm: 1.1.0 yargs-parser: 21.1.1 yocto-spinner: 0.2.3 @@ -16378,10 +16292,6 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.1.1: - dependencies: - balanced-match: 1.0.2 - brace-expansion@5.0.6: dependencies: balanced-match: 4.0.4 @@ -16412,10 +16322,6 @@ snapshots: dependencies: run-applescript: 7.1.0 - busboy@1.6.0: - dependencies: - streamsearch: 1.1.0 - bytes@3.1.2: {} c12@3.1.0: @@ -16644,11 +16550,6 @@ snapshots: core-util-is@1.0.3: {} - cors@2.8.6: - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - cosmiconfig-typescript-loader@6.3.0(@types/node@24.19.0)(cosmiconfig@9.0.2(typescript@6.0.3))(typescript@6.0.3): dependencies: '@types/node': 24.19.0 @@ -16875,11 +16776,6 @@ snapshots: dom-accessibility-api@0.6.3: {} - dom-helpers@5.2.1: - dependencies: - '@babel/runtime': 7.29.7 - csstype: 3.2.3 - dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 @@ -16892,12 +16788,14 @@ snapshots: dependencies: domelementtype: 2.3.0 - dompurify@3.1.7: {} - dompurify@3.4.12: optionalDependencies: '@types/trusted-types': 2.0.7 + dompurify@3.4.15: + optionalDependencies: + '@types/trusted-types': 2.0.7 + domutils@3.2.2: dependencies: dom-serializer: 2.0.0 @@ -17051,10 +16949,10 @@ snapshots: es-module-lexer@1.7.0: {} - es-module-lexer@2.1.0: {} - es-module-lexer@2.3.2: {} + es-module-lexer@3.0.2: {} + es-object-atoms@1.1.2: dependencies: es-errors: 1.3.0 @@ -17192,12 +17090,12 @@ snapshots: eslint-compat-utils@0.5.1(eslint@9.39.5(jiti@2.7.0)): dependencies: eslint: 9.39.5(jiti@2.7.0) - semver: 7.8.1 + semver: 7.8.5 eslint-compat-utils@0.6.5(eslint@9.39.5(jiti@2.7.0)): dependencies: eslint: 9.39.5(jiti@2.7.0) - semver: 7.8.1 + semver: 7.8.5 eslint-import-resolver-node@0.3.10: dependencies: @@ -17484,8 +17382,6 @@ snapshots: etag@1.8.1: {} - eventemitter3@4.0.7: {} - eventemitter3@5.0.4: {} events-universal@1.0.1: @@ -17550,8 +17446,6 @@ snapshots: fast-deep-equal@3.1.3: {} - fast-equals@5.4.0: {} - fast-fifo@1.3.2: {} fast-glob@3.3.3: @@ -17596,8 +17490,6 @@ snapshots: fastest-levenshtein@1.0.16: {} - fastify-plugin@5.1.0: {} - fastify-plugin@6.0.0: {} fastify@5.12.5: @@ -17626,10 +17518,6 @@ snapshots: dependencies: walk-up-path: 4.0.0 - fdir@6.5.0(picomatch@4.0.4): - optionalDependencies: - picomatch: 4.0.4 - fdir@6.5.0(picomatch@4.0.7): optionalDependencies: picomatch: 4.0.7 @@ -17644,7 +17532,7 @@ snapshots: file-selector@5.0.1: {} - file-type@21.3.4: + file-type@22.1.1: dependencies: '@tokenizer/inflate': 0.4.1 strtok3: 10.3.5 @@ -17720,14 +17608,6 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - form-data@4.0.5: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.4 - mime-types: 2.1.35 - form-data@4.0.6: dependencies: asynckit: 0.4.0 @@ -18145,8 +18025,6 @@ snapshots: hibp@15.2.1: {} - html-escaper@2.0.2: {} - html-escaper@3.0.3: {} html-void-elements@3.0.0: {} @@ -18391,19 +18269,6 @@ snapshots: isexe@2.0.0: {} - istanbul-lib-coverage@3.2.2: {} - - istanbul-lib-report@3.0.1: - dependencies: - istanbul-lib-coverage: 3.2.2 - make-dir: 4.0.0 - supports-color: 7.2.0 - - istanbul-reports@3.2.0: - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.1 - iterare@1.2.1: {} iterator.prototype@1.1.5: @@ -18437,11 +18302,11 @@ snapshots: js-tokens@4.0.0: {} - js-yaml@4.1.1: + js-yaml@4.3.2: dependencies: argparse: 2.0.1 - js-yaml@4.3.2: + js-yaml@5.4.2: dependencies: argparse: 2.0.1 @@ -18497,7 +18362,7 @@ snapshots: lodash.isstring: 4.0.1 lodash.once: 4.1.1 ms: 2.1.3 - semver: 7.8.1 + semver: 7.8.5 jspsych@7.3.4: dependencies: @@ -18591,36 +18456,69 @@ snapshots: lightningcss-android-arm64@1.32.0: optional: true + lightningcss-android-arm64@1.33.0: + optional: true + lightningcss-darwin-arm64@1.32.0: optional: true + lightningcss-darwin-arm64@1.33.0: + optional: true + lightningcss-darwin-x64@1.32.0: optional: true + lightningcss-darwin-x64@1.33.0: + optional: true + lightningcss-freebsd-x64@1.32.0: optional: true + lightningcss-freebsd-x64@1.33.0: + optional: true + lightningcss-linux-arm-gnueabihf@1.32.0: optional: true + lightningcss-linux-arm-gnueabihf@1.33.0: + optional: true + lightningcss-linux-arm64-gnu@1.32.0: optional: true + lightningcss-linux-arm64-gnu@1.33.0: + optional: true + lightningcss-linux-arm64-musl@1.32.0: optional: true + lightningcss-linux-arm64-musl@1.33.0: + optional: true + lightningcss-linux-x64-gnu@1.32.0: optional: true + lightningcss-linux-x64-gnu@1.33.0: + optional: true + lightningcss-linux-x64-musl@1.32.0: optional: true + lightningcss-linux-x64-musl@1.33.0: + optional: true + lightningcss-win32-arm64-msvc@1.32.0: optional: true + lightningcss-win32-arm64-msvc@1.33.0: + optional: true + lightningcss-win32-x64-msvc@1.32.0: optional: true + lightningcss-win32-x64-msvc@1.33.0: + optional: true + lightningcss@1.32.0: dependencies: detect-libc: 2.1.2 @@ -18637,11 +18535,27 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 + lightningcss@1.33.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 + lilconfig@2.1.0: {} lines-and-columns@1.2.4: {} - linkify-it@5.0.1: + linkify-it@5.0.2: dependencies: uc.micro: 2.1.0 @@ -18675,8 +18589,6 @@ snapshots: lodash.once@4.1.1: {} - lodash@4.18.1: {} - longest-streak@3.1.0: {} loose-envify@1.4.0: @@ -18691,15 +18603,11 @@ snapshots: dependencies: yallist: 3.1.1 - lucide-react@0.577.0(react@vendor+react@19.x): - dependencies: - react: link:vendor/react@19.x - - lucide-react@1.17.0(react@19.1.0): + lucide-react@1.49.0(react@19.1.0): dependencies: react: 19.1.0 - lucide-react@1.17.0(react@vendor+react@19.x): + lucide-react@1.49.0(react@vendor+react@19.x): dependencies: react: link:vendor/react@19.x @@ -18709,33 +18617,39 @@ snapshots: magic-string@0.30.17: dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.6.0 magic-string@0.30.21: dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.6.0 + + magic-string@1.4.2: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 magicast@0.5.3: dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 source-map-js: 1.2.1 - make-dir@3.1.0: + magicast@0.5.5: dependencies: - semver: 6.3.1 + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 + source-map-js: 1.2.1 - make-dir@4.0.0: + make-dir@3.1.0: dependencies: - semver: 7.8.1 + semver: 6.3.1 markdown-extensions@2.0.0: {} - markdown-it@14.2.0: + markdown-it@14.3.2: dependencies: argparse: 2.0.1 entities: 4.5.0 - linkify-it: 5.0.1 + linkify-it: 5.0.2 mdurl: 2.0.0 punycode.js: 2.3.1 uc.micro: 2.1.0 @@ -18935,8 +18849,6 @@ snapshots: mdurl@2.0.0: {} - media-typer@0.3.0: {} - media-typer@1.1.0: {} memory-pager@1.5.0: {} @@ -19254,17 +19166,13 @@ snapshots: dependencies: brace-expansion: 1.1.15 - minimatch@9.0.9: - dependencies: - brace-expansion: 2.1.1 - minimist@1.2.8: {} minipass@7.1.3: {} - monaco-editor@0.54.0: + monaco-editor@0.57.0: dependencies: - dompurify: 3.1.7 + dompurify: 3.4.15 marked: 14.0.0 mongodb-connection-string-url@7.0.2: @@ -19392,12 +19300,6 @@ snapshots: muggle-string@0.4.1: {} - multer@2.4.0: - dependencies: - append-field: 1.0.0 - busboy: 1.6.0 - type-is: 1.6.18 - nanoid@3.3.19: {} natural-compare@1.4.0: {} @@ -19506,7 +19408,7 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.2 - obug@2.1.2: {} + obug@2.2.1: {} ofetch@1.5.1: dependencies: @@ -19607,27 +19509,27 @@ snapshots: '@oxc-parser/binding-win32-ia32-msvc': 0.150.0 '@oxc-parser/binding-win32-x64-msvc': 0.150.0 - oxc-resolver@11.20.0: + oxc-resolver@11.21.2: optionalDependencies: - '@oxc-resolver/binding-android-arm-eabi': 11.20.0 - '@oxc-resolver/binding-android-arm64': 11.20.0 - '@oxc-resolver/binding-darwin-arm64': 11.20.0 - '@oxc-resolver/binding-darwin-x64': 11.20.0 - '@oxc-resolver/binding-freebsd-x64': 11.20.0 - '@oxc-resolver/binding-linux-arm-gnueabihf': 11.20.0 - '@oxc-resolver/binding-linux-arm-musleabihf': 11.20.0 - '@oxc-resolver/binding-linux-arm64-gnu': 11.20.0 - '@oxc-resolver/binding-linux-arm64-musl': 11.20.0 - '@oxc-resolver/binding-linux-ppc64-gnu': 11.20.0 - '@oxc-resolver/binding-linux-riscv64-gnu': 11.20.0 - '@oxc-resolver/binding-linux-riscv64-musl': 11.20.0 - '@oxc-resolver/binding-linux-s390x-gnu': 11.20.0 - '@oxc-resolver/binding-linux-x64-gnu': 11.20.0 - '@oxc-resolver/binding-linux-x64-musl': 11.20.0 - '@oxc-resolver/binding-openharmony-arm64': 11.20.0 - '@oxc-resolver/binding-wasm32-wasi': 11.20.0 - '@oxc-resolver/binding-win32-arm64-msvc': 11.20.0 - '@oxc-resolver/binding-win32-x64-msvc': 11.20.0 + '@oxc-resolver/binding-android-arm-eabi': 11.21.2 + '@oxc-resolver/binding-android-arm64': 11.21.2 + '@oxc-resolver/binding-darwin-arm64': 11.21.2 + '@oxc-resolver/binding-darwin-x64': 11.21.2 + '@oxc-resolver/binding-freebsd-x64': 11.21.2 + '@oxc-resolver/binding-linux-arm-gnueabihf': 11.21.2 + '@oxc-resolver/binding-linux-arm-musleabihf': 11.21.2 + '@oxc-resolver/binding-linux-arm64-gnu': 11.21.2 + '@oxc-resolver/binding-linux-arm64-musl': 11.21.2 + '@oxc-resolver/binding-linux-ppc64-gnu': 11.21.2 + '@oxc-resolver/binding-linux-riscv64-gnu': 11.21.2 + '@oxc-resolver/binding-linux-riscv64-musl': 11.21.2 + '@oxc-resolver/binding-linux-s390x-gnu': 11.21.2 + '@oxc-resolver/binding-linux-x64-gnu': 11.21.2 + '@oxc-resolver/binding-linux-x64-musl': 11.21.2 + '@oxc-resolver/binding-openharmony-arm64': 11.21.2 + '@oxc-resolver/binding-wasm32-wasi': 11.21.2 + '@oxc-resolver/binding-win32-arm64-msvc': 11.21.2 + '@oxc-resolver/binding-win32-x64-msvc': 11.21.2 oxc-resolver@11.24.2: optionalDependencies: @@ -19837,9 +19739,6 @@ snapshots: pngjs@5.0.0: {} - pngjs@7.0.0: - optional: true - possible-typed-array-names@1.1.0: {} postcss-load-config@3.1.4(postcss@8.5.28): @@ -20005,7 +19904,7 @@ snapshots: dependencies: '@babel/core': 7.29.7 '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.28.0 '@types/doctrine': 0.0.9 @@ -20065,7 +19964,15 @@ snapshots: react-is@17.0.2: {} - react-is@18.3.1: {} + react-is@19.1.0: {} + + react-redux@9.3.0(react@vendor+react@19.x)(redux@5.0.1): + dependencies: + '@types/use-sync-external-store': 0.0.6 + react: link:vendor/react@19.x + use-sync-external-store: 1.6.0(react@vendor+react@19.x) + optionalDependencies: + redux: 5.0.1 react-remove-scroll-bar@2.3.8(react@19.1.0): dependencies: @@ -20107,19 +20014,11 @@ snapshots: react: link:vendor/react@19.x react-dom: link:vendor/react-dom@19.x - react-resizable-panels@3.0.6(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x): + react-resizable-panels@4.14.1(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x): dependencies: react: link:vendor/react@19.x react-dom: link:vendor/react-dom@19.x - react-smooth@4.0.4(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x): - dependencies: - fast-equals: 5.4.0 - prop-types: 15.8.1 - react: link:vendor/react@19.x - react-dom: link:vendor/react-dom@19.x - react-transition-group: 4.4.5(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) - react-style-singleton@2.2.3(react@19.1.0): dependencies: get-nonce: 1.0.1 @@ -20132,15 +20031,6 @@ snapshots: react: link:vendor/react@19.x tslib: 2.8.1 - react-transition-group@4.4.5(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x): - dependencies: - '@babel/runtime': 7.29.7 - dom-helpers: 5.2.1 - loose-envify: 1.4.0 - prop-types: 15.8.1 - react: link:vendor/react@19.x - react-dom: link:vendor/react-dom@19.x - react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -20175,22 +20065,25 @@ snapshots: tiny-invariant: 1.3.3 tslib: 2.8.1 - recharts-scale@0.4.5: - dependencies: - decimal.js-light: 2.5.1 - - recharts@2.15.4(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x): + recharts@3.10.1(react-dom@vendor+react-dom@19.x)(react-is@19.1.0)(react@vendor+react@19.x)(redux@5.0.1): dependencies: + '@reduxjs/toolkit': 2.13.0(react-redux@9.3.0(react@vendor+react@19.x)(redux@5.0.1))(react@vendor+react@19.x) clsx: 2.1.1 - eventemitter3: 4.0.7 - lodash: 4.18.1 + decimal.js-light: 2.5.1 + es-toolkit: 1.52.0 + eventemitter3: 5.0.4 + immer: 11.1.18 react: link:vendor/react@19.x react-dom: link:vendor/react-dom@19.x - react-is: 18.3.1 - react-smooth: 4.0.4(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) - recharts-scale: 0.4.5 + react-is: 19.1.0 + react-redux: 9.3.0(react@vendor+react@19.x)(redux@5.0.1) + reselect: 5.2.0 tiny-invariant: 1.3.3 - victory-vendor: 36.9.2 + use-sync-external-store: 1.6.0(react@vendor+react@19.x) + victory-vendor: 37.3.6 + transitivePeerDependencies: + - '@types/react' + - redux recma-build-jsx@1.0.0: dependencies: @@ -20226,7 +20119,13 @@ snapshots: indent-string: 4.0.0 strip-indent: 3.0.0 - reflect-metadata@0.1.14: {} + redux-thunk@3.1.0(redux@5.0.1): + dependencies: + redux: 5.0.1 + + redux@5.0.1: {} + + reflect-metadata@0.2.2: {} reflect.getprototypeof@1.0.10: dependencies: @@ -20424,6 +20323,27 @@ snapshots: rfdc@1.4.1: {} + rolldown@1.2.12: + dependencies: + '@oxc-project/types': 0.152.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm-eabi': 1.2.12 + '@rolldown/binding-android-arm64': 1.2.12 + '@rolldown/binding-darwin-arm64': 1.2.12 + '@rolldown/binding-darwin-x64': 1.2.12 + '@rolldown/binding-freebsd-x64': 1.2.12 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.12 + '@rolldown/binding-linux-arm64-gnu': 1.2.12 + '@rolldown/binding-linux-arm64-musl': 1.2.12 + '@rolldown/binding-linux-ppc64-gnu': 1.2.12 + '@rolldown/binding-linux-s390x-gnu': 1.2.12 + '@rolldown/binding-linux-x64-gnu': 1.2.12 + '@rolldown/binding-linux-x64-musl': 1.2.12 + '@rolldown/binding-openharmony-arm64': 1.2.12 + '@rolldown/binding-win32-arm64-msvc': 1.2.12 + '@rolldown/binding-win32-x64-msvc': 1.2.12 + rollup@4.61.1: dependencies: '@types/estree': 1.0.9 @@ -20688,8 +20608,6 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 - siginfo@2.0.0: {} - signal-exit@4.1.0: {} simple-statistics@7.8.3: {} @@ -20790,40 +20708,36 @@ snapshots: dependencies: frac: 1.1.2 - stackback@0.0.2: {} - stacktrace-parser@0.1.11: dependencies: type-fest: 0.7.1 - state-local@1.0.7: {} - statuses@2.0.2: {} - std-env@4.1.0: {} + std-env@4.3.0: {} stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 internal-slot: 1.1.0 - storybook@10.5.6(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + storybook@10.6.1(prettier@3.9.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@testing-library/dom': 10.4.2 '@testing-library/jest-dom': 6.9.1 - '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.2) + '@testing-library/user-event': 14.6.7(@testing-library/dom@10.4.2) '@vitest/expect': 3.2.4 '@vitest/spy': 3.2.4 '@webcontainer/env': 1.1.1 - esbuild: 0.27.7 + esbuild: 0.28.2 jsonc-parser: 3.3.1 open: 10.2.0 oxc-parser: 0.127.0 - oxc-resolver: 11.20.0 + oxc-resolver: 11.21.2 recast: 0.23.11 - semver: 7.8.1 + semver: 7.8.5 use-sync-external-store: 1.6.0(react@19.1.0) ws: 8.22.0 optionalDependencies: @@ -20834,23 +20748,23 @@ snapshots: - react-dom - utf-8-validate - storybook@10.5.6(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x): + storybook@10.6.1(prettier@3.9.9)(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x): dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.2(react-dom@vendor+react-dom@19.x)(react@vendor+react@19.x) '@testing-library/dom': 10.4.2 '@testing-library/jest-dom': 6.9.1 - '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.2) + '@testing-library/user-event': 14.6.7(@testing-library/dom@10.4.2) '@vitest/expect': 3.2.4 '@vitest/spy': 3.2.4 '@webcontainer/env': 1.1.1 - esbuild: 0.27.7 + esbuild: 0.28.2 jsonc-parser: 3.3.1 open: 10.2.0 oxc-parser: 0.127.0 - oxc-resolver: 11.20.0 + oxc-resolver: 11.21.2 recast: 0.23.11 - semver: 7.8.1 + semver: 7.8.5 use-sync-external-store: 1.6.0(react@vendor+react@19.x) ws: 8.22.0 optionalDependencies: @@ -20861,8 +20775,6 @@ snapshots: - react-dom - utf-8-validate - streamsearch@1.1.0: {} - streamx@2.26.0: dependencies: events-universal: 1.0.1 @@ -20998,7 +20910,7 @@ snapshots: cookiejar: 2.1.4 debug: 4.4.3 fast-safe-stringify: 2.1.1 - form-data: 4.0.5 + form-data: 4.0.6 formidable: 3.5.4 methods: 1.1.2 mime: 2.6.0 @@ -21046,10 +20958,6 @@ snapshots: picocolors: 1.1.1 sax: 1.6.0 - swagger-ui-dist@5.32.6: - dependencies: - '@scarf/scarf': 1.4.0 - synckit@0.11.13: dependencies: '@pkgr/core': 0.3.6 @@ -21100,18 +21008,20 @@ snapshots: tiny-invariant@1.3.3: {} - tinybench@2.9.0: {} + tinybench@6.2.0: {} tinyexec@1.2.4: {} + tinyexec@1.3.1: {} + tinyglobby@0.2.17: dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 tinyrainbow@2.0.0: {} - tinyrainbow@3.1.0: {} + tinyrainbow@3.1.1: {} tinyspy@4.0.4: {} @@ -21206,11 +21116,6 @@ snapshots: dependencies: tagged-tag: 1.0.0 - type-is@1.6.18: - dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 - type-is@2.1.0: dependencies: content-type: 2.0.0 @@ -21250,16 +21155,16 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typedoc-plugin-markdown@4.4.2(typedoc@0.27.9(typescript@6.0.3)): + typedoc-plugin-markdown@4.13.1(typedoc@0.28.20(typescript@6.0.3)): dependencies: - typedoc: 0.27.9(typescript@6.0.3) + typedoc: 0.28.20(typescript@6.0.3) - typedoc@0.27.9(typescript@6.0.3): + typedoc@0.28.20(typescript@6.0.3): dependencies: - '@gerrit0/mini-shiki': 1.27.2 + '@gerrit0/mini-shiki': 3.23.0 lunr: 2.3.9 - markdown-it: 14.2.0 - minimatch: 9.0.9 + markdown-it: 14.3.2 + minimatch: 10.2.5 typescript: 6.0.3 yaml: 2.9.0 @@ -21267,7 +21172,7 @@ snapshots: typescript-auto-import-cache@0.3.6: dependencies: - semver: 7.8.1 + semver: 7.8.5 typescript-eslint@8.60.1(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3): dependencies: @@ -21305,8 +21210,6 @@ snapshots: uncrypto@0.1.3: {} - undici-types@6.21.0: {} - undici-types@7.24.6: {} unified@11.0.5: @@ -21393,18 +21296,19 @@ snapshots: dependencies: '@jridgewell/remapping': 2.3.5 acorn: 8.16.0 - picomatch: 4.0.4 + picomatch: 4.0.7 webpack-virtual-modules: 0.6.2 - unplugin@3.4.0(esbuild@0.28.2)(rollup@4.61.1)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)): + unplugin@3.4.0(esbuild@0.28.2)(rolldown@1.2.12)(rollup@4.61.1)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)): dependencies: '@jridgewell/remapping': 2.3.5 picomatch: 4.0.7 webpack-virtual-modules: 0.6.2 optionalDependencies: esbuild: 0.28.2 + rolldown: 1.2.12 rollup: 4.61.1 - vite: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + vite: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) unstorage@1.17.5(idb-keyval@6.3.0): dependencies: @@ -21502,7 +21406,7 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - victory-vendor@36.9.2: + victory-vendor@37.3.6: dependencies: '@types/d3-array': 3.2.2 '@types/d3-ease': 3.0.2 @@ -21519,20 +21423,20 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite-plugin-compression@0.5.1(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)): + vite-plugin-compression@0.5.1(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)): dependencies: chalk: 4.1.2 debug: 4.4.3 fs-extra: 10.1.0 - vite: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + vite: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) transitivePeerDependencies: - supports-color - vite@6.4.3(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0): + vite@6.4.3(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)(yaml@2.9.0): dependencies: esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 postcss: 8.5.28 rollup: 4.61.1 tinyglobby: 0.2.17 @@ -21540,55 +21444,48 @@ snapshots: '@types/node': 24.19.0 fsevents: 2.3.3 jiti: 2.7.0 - lightningcss: 1.32.0 + lightningcss: 1.33.0 tsx: 4.23.15 yaml: 2.9.0 - vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0): + vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0): dependencies: - esbuild: 0.28.2 - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 + lightningcss: 1.33.0 + picomatch: 4.0.7 postcss: 8.5.28 - rollup: 4.61.1 + rolldown: 1.2.12 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 24.19.0 + esbuild: 0.28.2 fsevents: 2.3.3 jiti: 2.7.0 - lightningcss: 1.32.0 tsx: 4.23.15 yaml: 2.9.0 - vitefu@1.1.3(vite@6.4.3(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)): + vitefu@1.1.3(vite@6.4.3(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)(yaml@2.9.0)): optionalDependencies: - vite: 6.4.3(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) + vite: 6.4.3(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)(yaml@2.9.0) - vitest@4.1.11(@types/node@24.19.0)(@vitest/coverage-v8@4.1.11)(happy-dom@20.11.15)(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)): + vitest@5.0.2(@types/node@24.19.0)(@vitest/coverage-v8@5.0.2)(happy-dom@20.11.15)(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.1.11 - '@vitest/mocker': 4.1.11(vite@7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.11 - '@vitest/runner': 4.1.11 - '@vitest/snapshot': 4.1.11 - '@vitest/spy': 4.1.11 - '@vitest/utils': 4.1.11 + '@types/chai': 5.2.3 + '@vitest/mocker': 5.0.2(vite@8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0)) + chai: 6.2.2 es-module-lexer: 2.3.2 expect-type: 1.4.0 - magic-string: 0.30.21 - obug: 2.1.2 - pathe: 2.0.3 - picomatch: 4.0.4 - std-env: 4.1.0 - tinybench: 2.9.0 - tinyexec: 1.2.4 + magic-string: 1.4.2 + obug: 2.2.1 + picomatch: 4.0.7 + std-env: 4.3.0 + tinybench: 6.2.0 + tinyexec: 1.3.1 tinyglobby: 0.2.17 - tinyrainbow: 3.1.0 - vite: 7.3.6(@types/node@24.19.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.15)(yaml@2.9.0) - why-is-node-running: 2.3.0 + vite: 8.3.1(@types/node@24.19.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.0) + why-is-node-running: 3.2.2 optionalDependencies: '@types/node': 24.19.0 - '@vitest/coverage-v8': 4.1.11(@vitest/browser@4.1.11)(vitest@4.1.11) + '@vitest/coverage-v8': 5.0.2(vitest@5.0.2) happy-dom: 20.11.15 transitivePeerDependencies: - msw @@ -21634,7 +21531,7 @@ snapshots: volar-service-typescript@0.0.70(@volar/language-service@2.4.28): dependencies: path-browserify: 1.0.1 - semver: 7.8.1 + semver: 7.8.5 typescript-auto-import-cache: 0.3.6 vscode-languageserver-textdocument: 1.0.12 vscode-nls: 5.2.0 @@ -21763,10 +21660,7 @@ snapshots: dependencies: isexe: 2.0.0 - why-is-node-running@2.3.0: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 + why-is-node-running@3.2.2: {} widest-line@5.0.0: dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index bab606153..407583fd7 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -13,7 +13,7 @@ allowBuilds: sharp: true blockExoticSubdeps: true catalog: - '@casl/ability': '^6.7.1' + '@casl/ability': '^7.0.1' '@commitlint/cli': '^21.2.3' '@commitlint/config-conventional': '^21.2.3' '@douglasneuroinformatics/esbuild-plugin-prisma': 'latest' @@ -44,16 +44,23 @@ catalog: tailwindcss: '4.3.3' tsx: '4.23.15' serialize-error: '^13.0.1' - vite: '^7.3.6' + vite: '^8.3.1' zustand: ^5.0.15 - '@storybook/addon-docs': '10.5.6' - '@storybook/addon-themes': '10.5.6' - '@storybook/react-vite': '10.5.6' - 'storybook': '10.5.6' + '@storybook/addon-docs': '^10.6.1' + '@storybook/addon-themes': '^10.6.1' + '@storybook/react-vite': '^10.6.1' + 'storybook': '^10.6.1' catalogs: react19: react: 19.1.0 react-dom: 19.1.0 + react-is: 19.1.0 +# storybook's published types import @storybook/react without depending on it. Hoisted, that import +# reaches a different peer variant than the stories use, TypeScript merges the two copies onto it, +# and every story's args become `any` (storybook/AGENTS.md). +hoistPattern: + - '*' + - '!@storybook/react' minimumReleaseAge: 10080 # 7 days minimumReleaseAgeExclude: - '@douglasneuroinformatics/*' diff --git a/runtime/v1/vitest.config.ts b/runtime/v1/vitest.config.ts index 0f3b3f888..9b4fd729a 100644 --- a/runtime/v1/vitest.config.ts +++ b/runtime/v1/vitest.config.ts @@ -1,6 +1,6 @@ import { defineProject, mergeConfig } from 'vitest/config'; -import baseConfig from '../../vitest.config'; +import { baseConfig } from '../../vitest.config'; export default mergeConfig( baseConfig, diff --git a/storybook/AGENTS.md b/storybook/AGENTS.md index 8b38b3f63..9464947ce 100644 --- a/storybook/AGENTS.md +++ b/storybook/AGENTS.md @@ -21,11 +21,29 @@ Note the asymmetry: `apps/web` is scanned from `src`, the other two only from `s `apps/gateway` and every other package are not scanned at all. Covering a new location means adding an entry to the `stories` array. +## `@storybook/react` must not be hoisted, or every story's `args` lose their types + +`pnpm-workspace.yaml` sets `hoistPattern: ['*', '!@storybook/react']`. Since Storybook 10.5.7 the +`storybook` package's own declarations import `@storybook/react` without depending on it (#1619). +Hoisted, that import resolves to `node_modules/.pnpm/node_modules/@storybook/react`, the peer +variant installed for this workspace's real `react`, which has no types: `react` ships none and +root `package.json` deletes `@types/react` (`vendor/AGENTS.md`). The stories reach a second variant, +paired with `vendor/react@19.x`, through `@storybook/react-vite`. TypeScript treats copies with the +same name and version as one package and keeps the first it loads, so every story is checked +against the copy without React types: `ComponentProps` does not resolve and +`StoryObj` gives `args` no type. **Remove the exclusion and every story's `args` +become `any` without an error**; only a callback in `args` fails, with TS7006 in the owning +package's `tsc`. + +A checkout installed before the exclusion keeps its hoisted link: `pnpm install` records the new +pattern but reports "Already up to date" and leaves the link in place. Delete the root +`node_modules` and install again; `node_modules/.pnpm/node_modules/@storybook/react` must not exist. + ## The `@` alias resolves by importer, and only for two apps -`vite.config.js` replaces the usual static alias with a `customResolver` that maps `@` to -`apps/playground/src` or `apps/web/src` depending on which file did the importing, and returns -`null` for everything else. **A `packages/react-core` story that imports `@/…` will fail to +`vite.config.js` replaces the usual static alias with a `source-root-alias` plugin (`enforce: 'pre'`) +that maps `@` to `apps/playground/src` or `apps/web/src` depending on which file did the importing, +and returns `null` for everything else. **A `packages/react-core` story that imports `@/…` will fail to resolve** — react-core has no `@` alias of its own, so import relatively or by package name there. ## Tailwind scans only the directories named in `config/globals.css` diff --git a/storybook/vite.config.js b/storybook/vite.config.js index b28e98392..5bd9728c9 100644 --- a/storybook/vite.config.js +++ b/storybook/vite.config.js @@ -7,35 +7,38 @@ import { defineConfig } from 'vite'; const playgroundSourceRoot = path.resolve(import.meta.dirname, '../apps/playground/src'); const webSourceRoot = path.resolve(import.meta.dirname, '../apps/web/src'); +/** @type {import('vite').Plugin} */ +const sourceRootAlias = { + enforce: 'pre', + name: 'source-root-alias', + resolveId(source, importer, options) { + if (source !== '@' && !source.startsWith('@/')) { + return null; + } + const sourceRoot = [playgroundSourceRoot, webSourceRoot].find((root) => importer?.startsWith(root)); + if (!sourceRoot) { + return null; + } + return this.resolve(sourceRoot + source.slice(1), importer, options); + } +}; + export default defineConfig({ build: { target: 'es2022' }, optimizeDeps: { - esbuildOptions: { - target: 'es2022' + rolldownOptions: { + transform: { + target: 'es2022' + } } }, plugins: [ + sourceRootAlias, runtime({ rootDir: import.meta.dirname }), tailwindcss() - ], - resolve: { - alias: [ - { - customResolver: async function (source, importer) { - if (importer?.startsWith(playgroundSourceRoot)) { - return this.resolve(source.replace('{{ROOT}}', playgroundSourceRoot)); - } else if (importer?.startsWith(webSourceRoot)) { - return this.resolve(source.replace('{{ROOT}}', webSourceRoot)); - } - return null; - }, - find: '@', - replacement: '{{ROOT}}' - } - ] - } + ] }); diff --git a/testing/src/pages/playground/index.page.ts b/testing/src/pages/playground/index.page.ts index 2a3f01d16..012ea8ad5 100644 --- a/testing/src/pages/playground/index.page.ts +++ b/testing/src/pages/playground/index.page.ts @@ -8,14 +8,37 @@ import { playgroundURL } from '../../support/env'; */ export class PlaygroundPage { readonly $ref: Page; + readonly editorPane: Locator; + /** The handle between the editor and preview panes, which resizes them. */ + readonly paneSeparator: Locator; /** The instrument preview, which runs on another origin than the editor. */ readonly preview: FrameLocator; readonly previewFrame: Locator; + readonly previewPane: Locator; constructor(page: Page) { this.$ref = page; + this.editorPane = page.getByTestId('editor-pane'); + this.paneSeparator = page.getByRole('separator'); this.previewFrame = page.getByTestId('preview-frame'); this.preview = page.frameLocator('[data-testid="preview-frame"]'); + this.previewPane = page.getByTestId('preview-pane'); + } + + /** Drags the pane separator to `x`, in page coordinates. */ + async dragPaneSeparatorTo(x: number): Promise { + const separator = (await this.paneSeparator.boundingBox())!; + const y = separator.y + separator.height / 2; + await this.$ref.mouse.move(separator.x + separator.width / 2, y); + await this.$ref.mouse.down(); + await this.$ref.mouse.move(x, y, { steps: 10 }); + await this.$ref.mouse.up(); + } + + /** The editor's share of the width the editor and preview panes divide between them, from 0 to 1. */ + async editorShare(): Promise { + const [editor, preview] = await Promise.all([this.editorPane.boundingBox(), this.previewPane.boundingBox()]); + return editor!.width / (editor!.width + preview!.width); } /** Opens the editor, or a share link built against {@link playgroundURL}. */ diff --git a/testing/src/specs/playground.spec.ts b/testing/src/specs/playground.spec.ts index 0a143a0d3..f5d63c5cd 100644 --- a/testing/src/specs/playground.spec.ts +++ b/testing/src/specs/playground.spec.ts @@ -245,4 +245,22 @@ test.describe('playground', () => { await expect(playground.preview.getByText('Pet Name Measure')).toBeVisible(); }); + + // react-resizable-panels reads a bare number as pixels, so a pane size written as `66` rather than + // `"66%"` still type-checks and renders, only at the wrong size. + test('should split the editor and preview two to one, and stop the editor at a quarter when dragged narrower', async ({ + page + }) => { + const playground = new PlaygroundPage(page); + await playground.goto(); + await expect(playground.editorPane).toBeVisible({ timeout: PREVIEW_TIMEOUT }); + await expect.poll(() => playground.editorShare()).toBeCloseTo(0.66, 1); + + const editor = (await playground.editorPane.boundingBox())!; + await playground.dragPaneSeparatorTo(editor.x + editor.width / 2); + await expect.poll(() => playground.editorShare()).toBeCloseTo(0.33, 1); + + await playground.dragPaneSeparatorTo(editor.x); + await expect.poll(() => playground.editorShare()).toBeCloseTo(0.25, 1); + }); }); diff --git a/vitest.config.ts b/vitest.config.ts index 3a36a639a..875df0e93 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,37 +1,47 @@ import path from 'path'; -import { defineConfig } from 'vitest/config'; +import { defineConfig, mergeConfig } from 'vitest/config'; -export default defineConfig({ +// Project configs merge this rather than the default export, because Vitest 5 treats a `projects` +// field inside a referenced project config as a nested set of projects. +export const baseConfig = defineConfig({ test: { - coverage: { - exclude: [ - '**/coverage/**', - '**/dist/**', - '**/node_modules/**', - '**/public/**', - '**/scripts/**', - '**/*.d.?(c|m)ts', - '**/*{.,-}{test,test-d,spec}.?(c|m)[jt]s?(x)', - '**/*.config.?(c|m)[jt]s?(x)', - '**/*.stories.?(c|m)[jt]s?(x)', - '**/__tests__/**', - 'apps/gateway/src/entry-client.tsx', - 'apps/gateway/src/main.ts', - 'apps/web/src/main.tsx', - 'apps/web/src/route-tree.ts', - 'apps/web/src/testing/**' - ], - include: ['apps/{api,gateway,web}/src/**/*.?(c|m)[jt]s?(x)', 'packages/*/src/**/*.?(c|m)[jt]s?(x)'], - provider: 'v8', - reportsDirectory: path.resolve(import.meta.dirname, 'coverage'), - skipFull: true, - thresholds: { - 100: true - } - }, include: ['**/*.{test,spec}.?(c|m)[jt]s?(x)'], - projects: ['apps/*/vitest.config.ts', 'packages/*/vitest.config.ts', 'runtime/*/vitest.config.ts'], watch: false } }); + +export default mergeConfig( + baseConfig, + defineConfig({ + test: { + coverage: { + exclude: [ + '**/coverage/**', + '**/dist/**', + '**/node_modules/**', + '**/public/**', + '**/scripts/**', + '**/*.d.?(c|m)ts', + '**/*{.,-}{test,test-d,spec}.?(c|m)[jt]s?(x)', + '**/*.config.?(c|m)[jt]s?(x)', + '**/*.stories.?(c|m)[jt]s?(x)', + '**/__tests__/**', + 'apps/gateway/src/entry-client.tsx', + 'apps/gateway/src/main.ts', + 'apps/web/src/main.tsx', + 'apps/web/src/route-tree.ts', + 'apps/web/src/testing/**' + ], + include: ['apps/{api,gateway,web}/src/**/*.?(c|m)[jt]s?(x)', 'packages/*/src/**/*.?(c|m)[jt]s?(x)'], + provider: 'v8', + reportsDirectory: path.resolve(import.meta.dirname, 'coverage'), + skipFull: true, + thresholds: { + 100: true + } + }, + projects: ['apps/*/vitest.config.ts', 'packages/*/vitest.config.ts', 'runtime/*/vitest.config.ts'] + } + }) +);