diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f31c3fcb..e50dec7a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,8 +52,8 @@ jobs: - name: Enable Corepack run: corepack enable - - name: Install dependencies - run: pnpm install --no-frozen-lockfile + - name: Install reproducible dependencies + run: pnpm install --frozen-lockfile - name: Check formatting run: pnpm format:check diff --git a/.gitignore b/.gitignore index 385a0b13..44650a00 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ node_modules/ .next/ dist/ coverage/ +*.tsbuildinfo .env .env.* !.env.example diff --git a/CHANGELOG.md b/CHANGELOG.md index db2bd63d..82005ac9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to LifeOS are documented in this file. ### Added +- Executable AI-service JSDoc and exact 100% statement, branch, function, and line coverage gates, with an operator-facing governance assurance boundary. - Tenant-safe durable planning search across goals, projects, and tasks, with Unicode-normalized exact, prefix, and whole-token matching. - An authenticated same-origin planning-search boundary that signs the session-derived workspace context and forwards no browser credential to planning-service. - An accessible quick-capture and search surface that keeps browser-local Today drafts visibly separate from durable workspace records. @@ -18,6 +19,7 @@ All notable changes to LifeOS are documented in this file. ### Fixed +- Stale AI proposal revision conflicts now belong to the technology-independent audit domain while the PostgreSQL adapter preserves its compatibility export. - Planning search now normalizes browser query text and prevents stale or unmounted requests from replacing the latest visible result state. - Reminder fatigue deferral now crosses long IANA offset fallbacks and next-day quiet hours without abandoning the claimed occurrence. - Notification workers now recover expired claims and exact delivery replays without creating duplicate inbox messages. diff --git a/apps/ai-service/package.json b/apps/ai-service/package.json index ec0470dc..e93cb5b6 100644 --- a/apps/ai-service/package.json +++ b/apps/ai-service/package.json @@ -4,10 +4,11 @@ "private": true, "scripts": { "build": "nest build", - "dev": "nest start --watch", - "lint": "tsc --noEmit", - "test": "vitest run --passWithNoTests --no-file-parallelism", - "typecheck": "tsc --noEmit" + "dev": "nest start --watch --entryFile server", + "lint": "tsc --noEmit && prettier --single-quote --check package.json tsconfig.json vitest.config.ts \"src/**/*.ts\" ../../docs/operations/ai-proposal-audit-assurance.md ../../docs/superpowers/specs/2026-08-04-ai-service-quality-gates-design.md ../../docs/superpowers/plans/2026-08-04-ai-service-quality-gates.md", + "test": "vitest run --no-file-parallelism --coverage", + "typecheck": "tsc --noEmit", + "start": "node dist/server.js" }, "dependencies": { "@nestjs/common": "^11.1.6", @@ -21,6 +22,7 @@ "@nestjs/cli": "^11.0.10", "@types/node": "^24.3.0", "@types/pg": "^8.20.0", + "@vitest/coverage-v8": "^3.2.4", "typescript": "^5.9.2", "vitest": "^3.2.4" } diff --git a/apps/ai-service/src/ai-runtime.ts b/apps/ai-service/src/ai-runtime.ts index e07634e3..f563f14b 100644 --- a/apps/ai-service/src/ai-runtime.ts +++ b/apps/ai-service/src/ai-runtime.ts @@ -11,6 +11,7 @@ import { ProposalService, RuleBasedProposalModel } from './proposal-service'; const MAXIMUM_CONFIGURATION_LENGTH = 8 * 1024; const databaseLogger = new Logger('AiDatabasePool'); +/** Bounded environment values accepted by the AI production runtime. */ type RuntimeEnvironment = Readonly>; /** Bounded PostgreSQL pool boundary used by the AI production runtime. */ @@ -44,6 +45,7 @@ export function createAiPoolErrorListener( /** Adapts node-postgres to the minimal pool contract required by the AI service. */ class NodePostgresAiPool implements AiPool { + /** Creates the bounded adapter around one owned node-postgres pool. */ constructor(private readonly pool: Pool) {} /** Executes SQL without exposing the wider node-postgres client surface. */ @@ -63,6 +65,7 @@ class NodePostgresAiPool implements AiPool { /** Narrows the runtime pool to the repository's parameterized SQL contract. */ class NodePostgresProposalAuditSqlClient implements ProposalAuditSqlClient { + /** Creates the repository SQL adapter over the runtime-owned pool. */ constructor(private readonly pool: AiPool) {} /** Delegates one parameterized query through the bounded pool interface. */ diff --git a/apps/ai-service/src/docstring-coverage.test.ts b/apps/ai-service/src/docstring-coverage.test.ts new file mode 100644 index 00000000..b48e2076 --- /dev/null +++ b/apps/ai-service/src/docstring-coverage.test.ts @@ -0,0 +1,163 @@ +import { readdir, readFile } from 'node:fs/promises'; +import { resolve } from 'node:path'; +import * as ts from 'typescript'; +import { describe, expect, it } from 'vitest'; + +/** One production declaration missing an explanatory JSDoc block. */ +interface UndocumentedDeclaration { + readonly file: string; + readonly line: number; + readonly declaration: string; +} + +/** Reports whether the declaration's leading trivia ends with one JSDoc block. */ +function hasJSDoc(node: ts.Node, sourceFile: ts.SourceFile): boolean { + const leadingTrivia = sourceFile.text.slice( + node.getFullStart(), + node.getStart(sourceFile), + ); + return /\/\*\*[\s\S]*?\*\/\s*$/u.test(leadingTrivia); +} + +/** Maps a callable variable declaration to the owning statement carrying JSDoc. */ +function documentationOwner(node: ts.Node): ts.Node { + if ( + ts.isVariableDeclaration(node) && + ts.isVariableDeclarationList(node.parent) && + ts.isVariableStatement(node.parent.parent) + ) { + return node.parent.parent; + } + return node; +} + +/** Identifies callable variable or property initializers that require documentation. */ +function hasCallableInitializer( + node: ts.VariableDeclaration | ts.PropertyDeclaration, +): boolean { + return ( + node.initializer !== undefined && + (ts.isArrowFunction(node.initializer) || + ts.isFunctionExpression(node.initializer)) + ); +} + +/** Produces a stable human-readable name for a documentation failure. */ +function declarationName(node: ts.Node): string { + if (ts.isConstructorDeclaration(node)) { + const parent = node.parent; + return ts.isClassDeclaration(parent) && parent.name + ? `${parent.name.text}.constructor` + : 'constructor'; + } + if ( + ts.isVariableDeclaration(node) || + ts.isPropertyDeclaration(node) || + ts.isFunctionDeclaration(node) || + ts.isClassDeclaration(node) || + ts.isInterfaceDeclaration(node) || + ts.isTypeAliasDeclaration(node) || + ts.isMethodDeclaration(node) || + ts.isMethodSignature(node) + ) { + return node.name?.getText() ?? node.kind.toString(); + } + return node.kind.toString(); +} + +/** Identifies production declaration kinds that require explanatory JSDoc. */ +function requiresJSDoc(node: ts.Node): boolean { + return ( + ts.isFunctionDeclaration(node) || + ts.isClassDeclaration(node) || + ts.isInterfaceDeclaration(node) || + ts.isTypeAliasDeclaration(node) || + ts.isMethodDeclaration(node) || + ts.isMethodSignature(node) || + ts.isConstructorDeclaration(node) || + (ts.isVariableDeclaration(node) && hasCallableInitializer(node)) || + (ts.isPropertyDeclaration(node) && hasCallableInitializer(node)) + ); +} + +/** Restricts the contract to top-level declarations and class/interface members. */ +function isDocumentedScope(node: ts.Node, sourceFile: ts.SourceFile): boolean { + const owner = documentationOwner(node); + return ( + owner.parent === sourceFile || + ts.isClassDeclaration(node.parent) || + ts.isInterfaceDeclaration(node.parent) + ); +} + +/** Collects every undocumented production declaration from one TypeScript source. */ +function collectUndocumentedDeclarations( + file: string, + source: string, +): UndocumentedDeclaration[] { + const sourceFile = ts.createSourceFile( + file, + source, + ts.ScriptTarget.Latest, + true, + ts.ScriptKind.TS, + ); + const missing: UndocumentedDeclaration[] = []; + + /** Visits one syntax node and records any in-scope documentation failure. */ + function visit(node: ts.Node): void { + if ( + requiresJSDoc(node) && + isDocumentedScope(node, sourceFile) && + !hasJSDoc(documentationOwner(node), sourceFile) + ) { + const position = sourceFile.getLineAndCharacterOfPosition( + node.getStart(sourceFile), + ); + missing.push({ + file, + line: position.line + 1, + declaration: declarationName(node), + }); + } + ts.forEachChild(node, visit); + } + + visit(sourceFile); + return missing; +} + +/** Discovers production TypeScript sources while excluding all test fixtures. */ +async function discoverSourceFiles(directory: string): Promise { + const entries = await readdir(directory, { withFileTypes: true }); + const files = await Promise.all( + entries.map(async (entry) => { + const path = resolve(directory, entry.name); + if (entry.isDirectory()) { + return await discoverSourceFiles(path); + } + return entry.isFile() && + entry.name.endsWith('.ts') && + !entry.name.endsWith('.test.ts') + ? [path] + : []; + }), + ); + return files.flat().sort(); +} + +describe('ai-service source documentation', () => { + it('documents every production declaration with JSDoc', async () => { + const sourceFiles = await discoverSourceFiles(__dirname); + const missing = ( + await Promise.all( + sourceFiles.map(async (path) => { + const source = await readFile(path, 'utf8'); + return collectUndocumentedDeclarations(path, source); + }), + ) + ).flat(); + + expect(missing).toEqual([]); + }); +}); diff --git a/apps/ai-service/src/main.ts b/apps/ai-service/src/main.ts index 942d4fb6..2e4a54d7 100644 --- a/apps/ai-service/src/main.ts +++ b/apps/ai-service/src/main.ts @@ -21,6 +21,7 @@ import { import { type ProposalAuditRecord, ProposalAuditValidationError, + ProposalDigestMismatchError, type ProposalDecisionEvent, } from './proposal-audit-domain'; import { @@ -34,7 +35,6 @@ import { import { ProposalAuditPersistenceError, ProposalDecisionConflictError, - ProposalDigestMismatchError, } from './postgres-proposal-audit-repository'; /** Injection token for the narrowed inert proposal-generation contract. */ @@ -47,7 +47,7 @@ export const AI_RUNTIME = Symbol('AI_RUNTIME'); const auditLogger = new Logger('AiProposalAudit'); /** Narrow read-only proposal-generation contract exposed to the legacy controller. */ -interface ProposalGenerator { +export interface ProposalGenerator { /** Generates an inert proposal without executing any proposed operation. */ generateProposal( workspaceId: string, @@ -273,13 +273,41 @@ export class AiAppModule {} }) export class AiProductionModule {} -/** Boots the production AI process with exactly-once shutdown hooks. */ -async function bootstrap(): Promise { - const app = await NestFactory.create(AiProductionModule); - app.enableShutdownHooks(); - await app.listen(Number(process.env.AI_SERVICE_PORT ?? 4105), '0.0.0.0'); +/** Minimal Nest application behavior needed by the AI process bootstrap. */ +export interface AiBootstrapApplication { + /** Enables Nest-managed lifecycle shutdown hooks. */ + enableShutdownHooks(): void; + /** Starts the HTTP server on one validated port and fixed host. */ + listen(port: number, host: string): Promise; +} + +/** Factory used to construct the production Nest application. */ +export type AiApplicationFactory = () => Promise; + +/** Creates the production Nest application without starting its listener. */ +export async function createAiApplication(): Promise { + return await NestFactory.create(AiProductionModule); } -if (require.main === module) { - void bootstrap(); +/** Parses the optional AI service port into the supported TCP range. */ +export function resolveAiServicePort(value: string | undefined): number { + if (value === undefined || value.trim() === '') { + return 4_105; + } + const parsed = Number(value); + if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > 65_535) { + throw new Error('AI service port is invalid'); + } + return parsed; +} + +/** Boots the production AI process with exactly-once shutdown hooks. */ +export async function bootstrapAiService( + environment: Readonly> = process.env, + applicationFactory: AiApplicationFactory = createAiApplication, +): Promise { + const port = resolveAiServicePort(environment.AI_SERVICE_PORT); + const app = await applicationFactory(); + app.enableShutdownHooks(); + await app.listen(port, '0.0.0.0'); } diff --git a/apps/ai-service/src/postgres-proposal-audit-repository.ts b/apps/ai-service/src/postgres-proposal-audit-repository.ts index cae3f5ab..6ab5ea41 100644 --- a/apps/ai-service/src/postgres-proposal-audit-repository.ts +++ b/apps/ai-service/src/postgres-proposal-audit-repository.ts @@ -1,12 +1,14 @@ import { type ProposalAuditRecord, type ProposalAuditRepository, - ProposalAuditValidationError, + ProposalDigestMismatchError, type ProposalDecisionEvent, validateProposalAuditRecord, validateProposalDecisionEvent, } from './proposal-audit-domain'; +export { ProposalDigestMismatchError } from './proposal-audit-domain'; + /** Minimal parameterized SQL result boundary for proposal audit persistence. */ export interface ProposalAuditSqlQueryResult { rows: Row[]; @@ -14,12 +16,14 @@ export interface ProposalAuditSqlQueryResult { /** Minimal parameterized SQL client boundary for proposal audit persistence. */ export interface ProposalAuditSqlClient { + /** Executes one parameterized SQL statement and returns bounded rows. */ query( text: string, values: readonly unknown[], ): Promise>; } +/** Untrusted PostgreSQL row for one immutable proposal revision. */ interface ProposalAuditRow { proposal_id: unknown; workspace_id: unknown; @@ -35,6 +39,7 @@ interface ProposalAuditRow { recorded_at: unknown; } +/** Untrusted PostgreSQL row for one append-only proposal decision. */ interface ProposalDecisionRow { id: unknown; workspace_id: unknown; @@ -48,6 +53,7 @@ interface ProposalDecisionRow { recorded_at: unknown; } +/** Minimal PostgreSQL error classification used for named constraint mapping. */ interface PostgreSqlErrorShape { code?: unknown; constraint?: unknown; @@ -61,32 +67,37 @@ const DIGEST_FOREIGN_KEY_CONSTRAINT = /** Credential-free failure for malformed rows and database errors. */ export class ProposalAuditPersistenceError extends Error { + /** Creates a stable credential-free database failure. */ constructor() { super('Proposal audit persistence operation failed'); this.name = 'ProposalAuditPersistenceError'; } } -/** Raised when a decision references a stale or unknown proposal digest. */ -export class ProposalDigestMismatchError extends Error { - constructor() { - super('Proposal content digest does not match persisted evidence'); - this.name = 'ProposalDigestMismatchError'; - } -} - /** Raised when one decision idempotency key is reused with another payload. */ export class ProposalDecisionConflictError extends Error { + /** Creates a stable conflict for non-identical idempotency replay. */ constructor() { super('Proposal decision idempotency key conflicts with an earlier event'); this.name = 'ProposalDecisionConflictError'; } } +/** Raises the shared credential-free persistence failure. */ function invalidPersistence(): never { throw new ProposalAuditPersistenceError(); } +/** Maps any malformed boundary value to the stable persistence failure. */ +function mapPersistenceValidation(operation: () => Value): Value { + try { + return operation(); + } catch { + return invalidPersistence(); + } +} + +/** Requires a canonical UUIDv4 at the SQL boundary. */ function requireUuidV4(value: unknown): string { if (typeof value !== 'string') { return invalidPersistence(); @@ -98,12 +109,14 @@ function requireUuidV4(value: unknown): string { return normalized; } +/** Verifies that a persisted identifier remains within the requested tenant scope. */ function requireExpected(actual: string, expected: string): void { if (actual !== expected.toLowerCase()) { invalidPersistence(); } } +/** Accepts zero or one row and rejects impossible duplicate identities. */ function oneOrUndefined(rows: Row[]): Row | undefined { if (rows.length > 1) { invalidPersistence(); @@ -111,10 +124,12 @@ function oneOrUndefined(rows: Row[]): Row | undefined { return rows[0]; } +/** Requires exactly one row for a successful state transition or replay. */ function exactlyOne(rows: Row[]): Row { return oneOrUndefined(rows) ?? invalidPersistence(); } +/** Matches only one PostgreSQL code and reviewed constraint name. */ function isNamedDatabaseError( error: unknown, code: string, @@ -127,13 +142,14 @@ function isNamedDatabaseError( return candidate.code === code && candidate.constraint === constraint; } +/** Validates and tenant-checks one untrusted proposal row. */ function parseProposalRow( row: ProposalAuditRow, - expectedWorkspaceId?: string, + expectedWorkspaceId: string, expectedProposalId?: string, ): ProposalAuditRecord { - try { - const record = validateProposalAuditRecord({ + const record = mapPersistenceValidation(() => + validateProposalAuditRecord({ proposal: { proposalId: row.proposal_id, workspaceId: row.workspace_id, @@ -148,88 +164,64 @@ function parseProposalRow( requestDigest: row.request_digest, contentDigest: row.content_digest, recordedAt: row.recorded_at, - }); - if (expectedWorkspaceId) { - requireExpected(record.proposal.workspaceId, expectedWorkspaceId); - } - if (expectedProposalId) { - requireExpected(record.proposal.proposalId, expectedProposalId); - } - return record; - } catch (error) { - if (error instanceof ProposalAuditValidationError) { - return invalidPersistence(); - } - throw error; + }), + ); + requireExpected(record.proposal.workspaceId, expectedWorkspaceId); + if (expectedProposalId) { + requireExpected(record.proposal.proposalId, expectedProposalId); } + return record; } +/** Validates and tenant-checks one untrusted decision row. */ function parseDecisionRow( row: ProposalDecisionRow, - expectedWorkspaceId?: string, + expectedWorkspaceId: string, expectedProposalId?: string, expectedIdempotencyKey?: string, ): ProposalDecisionEvent { - try { - const value = { - id: row.id, - workspaceId: row.workspace_id, - proposalId: row.proposal_id, - proposalContentDigest: row.proposal_content_digest, - actorId: row.actor_id, - decision: row.decision_kind, - ...(row.reason_text === null || row.reason_text === undefined - ? {} - : { reason: row.reason_text }), - idempotencyKey: row.idempotency_key, - decidedAt: row.decided_at, - recordedAt: row.recorded_at, - }; - const event = validateProposalDecisionEvent(value); - if (expectedWorkspaceId) { - requireExpected(event.workspaceId, expectedWorkspaceId); - } - if (expectedProposalId) { - requireExpected(event.proposalId, expectedProposalId); - } - if (expectedIdempotencyKey) { - requireExpected(event.idempotencyKey, expectedIdempotencyKey); - } - return event; - } catch (error) { - if (error instanceof ProposalAuditValidationError) { - return invalidPersistence(); - } - throw error; + const value = { + id: row.id, + workspaceId: row.workspace_id, + proposalId: row.proposal_id, + proposalContentDigest: row.proposal_content_digest, + actorId: row.actor_id, + decision: row.decision_kind, + ...(row.reason_text === null || row.reason_text === undefined + ? {} + : { reason: row.reason_text }), + idempotencyKey: row.idempotency_key, + decidedAt: row.decided_at, + recordedAt: row.recorded_at, + }; + const event = mapPersistenceValidation(() => + validateProposalDecisionEvent(value), + ); + requireExpected(event.workspaceId, expectedWorkspaceId); + if (expectedProposalId) { + requireExpected(event.proposalId, expectedProposalId); } + if (expectedIdempotencyKey) { + requireExpected(event.idempotencyKey, expectedIdempotencyKey); + } + return event; } +/** Maps malformed proposal input to the stable persistence error contract. */ function validateProposalInput( record: ProposalAuditRecord, ): ProposalAuditRecord { - try { - return validateProposalAuditRecord(record); - } catch (error) { - if (error instanceof ProposalAuditValidationError) { - return invalidPersistence(); - } - throw error; - } + return mapPersistenceValidation(() => validateProposalAuditRecord(record)); } +/** Maps malformed decision input to the stable persistence error contract. */ function validateDecisionInput( event: ProposalDecisionEvent, ): ProposalDecisionEvent { - try { - return validateProposalDecisionEvent(event); - } catch (error) { - if (error instanceof ProposalAuditValidationError) { - return invalidPersistence(); - } - throw error; - } + return mapPersistenceValidation(() => validateProposalDecisionEvent(event)); } +/** Compares every immutable decision field relevant to exact idempotent replay. */ function sameDecisionPayload( persisted: ProposalDecisionEvent, attempted: ProposalDecisionEvent, @@ -245,8 +237,10 @@ function sameDecisionPayload( /** Parameterized, tenant-scoped PostgreSQL proposal audit repository. */ export class PostgresProposalAuditRepository implements ProposalAuditRepository { + /** Creates the repository over one bounded parameterized SQL client. */ constructor(private readonly client: ProposalAuditSqlClient) {} + /** Executes SQL while replacing transport details with one stable failure. */ private async query( text: string, values: readonly unknown[], @@ -258,6 +252,7 @@ export class PostgresProposalAuditRepository implements ProposalAuditRepository } } + /** Persists one immutable tenant-scoped proposal revision. */ async saveProposal(record: ProposalAuditRecord): Promise { const safe = validateProposalInput(record); await this.query( @@ -283,6 +278,7 @@ export class PostgresProposalAuditRepository implements ProposalAuditRepository ); } + /** Finds one tenant-scoped proposal revision with duplicate-row rejection. */ async findProposal( workspaceId: string, proposalId: string, @@ -304,6 +300,7 @@ export class PostgresProposalAuditRepository implements ProposalAuditRepository : undefined; } + /** Lists tenant proposal evidence in deterministic creation order. */ async listProposals(workspaceId: string): Promise { const safeWorkspaceId = requireUuidV4(workspaceId); const result = await this.query( @@ -318,6 +315,7 @@ export class PostgresProposalAuditRepository implements ProposalAuditRepository return result.rows.map((row) => parseProposalRow(row, safeWorkspaceId)); } + /** Appends one decision or returns an exact idempotent replay. */ async appendDecision( event: ProposalDecisionEvent, ): Promise { @@ -386,6 +384,7 @@ export class PostgresProposalAuditRepository implements ProposalAuditRepository return persisted; } + /** Lists append-only tenant decision history in deterministic order. */ async listDecisions( workspaceId: string, proposalId: string, diff --git a/apps/ai-service/src/proposal-audit-application.ts b/apps/ai-service/src/proposal-audit-application.ts index 4360baa4..bf42a389 100644 --- a/apps/ai-service/src/proposal-audit-application.ts +++ b/apps/ai-service/src/proposal-audit-application.ts @@ -8,13 +8,13 @@ import { createProposalAuditRecord, createProposalDecisionEvent, ProposalAuditValidationError, + ProposalDigestMismatchError, } from './proposal-audit-domain'; import { type AuditableProposal, type ProposalRequest, ProposalService, } from './proposal-service'; -import { ProposalDigestMismatchError } from './postgres-proposal-audit-repository'; const UUID_V4_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; @@ -39,6 +39,7 @@ export type ProposalDecisionIdFactory = () => string; /** Stable tenant-scoped absence used by bounded HTTP problem mapping. */ export class ProposalAuditNotFoundError extends Error { + /** Creates a stable tenant-safe absence without disclosing another workspace. */ constructor() { super('Proposal audit record was not found'); this.name = 'ProposalAuditNotFoundError'; diff --git a/apps/ai-service/src/proposal-audit-domain.test.ts b/apps/ai-service/src/proposal-audit-domain.test.ts index 8ea4e60a..34b0cb3c 100644 --- a/apps/ai-service/src/proposal-audit-domain.test.ts +++ b/apps/ai-service/src/proposal-audit-domain.test.ts @@ -6,6 +6,7 @@ import { createProposalAuditRecord, createProposalDecisionEvent, ProposalAuditValidationError, + ProposalDigestMismatchError, validateProposalAuditRecord, validateProposalDecisionEvent, } from './proposal-audit-domain'; @@ -152,6 +153,13 @@ describe('proposal audit domain', () => { expect(Object.isFrozen(decision)).toBe(true); }); + it('owns stale immutable revision semantics in the audit domain', () => { + expect(new ProposalDigestMismatchError()).toMatchObject({ + name: 'ProposalDigestMismatchError', + message: 'Proposal content digest does not match persisted evidence', + }); + }); + it('rejects numeric identifiers and malformed decision digests', () => { expect(() => createProposalDecisionEvent({ diff --git a/apps/ai-service/src/proposal-audit-domain.ts b/apps/ai-service/src/proposal-audit-domain.ts index c7478171..9738edf3 100644 --- a/apps/ai-service/src/proposal-audit-domain.ts +++ b/apps/ai-service/src/proposal-audit-domain.ts @@ -1,14 +1,10 @@ import { createHash } from 'node:crypto'; import type { AuditableProposal, - ProposalContextItem, ProposalOperation, ProposalRequest, } from './proposal-service'; -import { - ProposalValidationError, - validateProposalRequest, -} from './proposal-service'; +import { validateProposalRequest } from './proposal-service'; const UUID_V4_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; @@ -46,13 +42,18 @@ export interface ProposalDecisionEvent { /** Asynchronous audit-only persistence contract with no user-data mutation API. */ export interface ProposalAuditRepository { + /** Persists one immutable proposal revision and its canonical provenance. */ saveProposal(record: ProposalAuditRecord): Promise; + /** Finds one tenant-owned immutable proposal revision. */ findProposal( workspaceId: string, proposalId: string, ): Promise; + /** Lists deterministic proposal evidence for one workspace. */ listProposals(workspaceId: string): Promise; + /** Appends or exactly replays one immutable decision event. */ appendDecision(event: ProposalDecisionEvent): Promise; + /** Lists append-only decision history for one tenant-owned proposal. */ listDecisions( workspaceId: string, proposalId: string, @@ -61,16 +62,28 @@ export interface ProposalAuditRepository { /** Stable failure for malformed proposal-audit input or persisted evidence. */ export class ProposalAuditValidationError extends Error { + /** Creates a stable credential-free audit validation failure. */ constructor() { super('Proposal audit evidence is invalid'); this.name = 'ProposalAuditValidationError'; } } +/** Raised when a decision references a stale or unknown proposal digest. */ +export class ProposalDigestMismatchError extends Error { + /** Creates a stable conflict representing an immutable revision mismatch. */ + constructor() { + super('Proposal content digest does not match persisted evidence'); + this.name = 'ProposalDigestMismatchError'; + } +} + +/** Raises the shared bounded audit validation failure. */ function invalid(): never { throw new ProposalAuditValidationError(); } +/** Requires an object-shaped untrusted or persisted value. */ function requireRecord(value: unknown): Readonly> { if (typeof value !== 'object' || value === null || Array.isArray(value)) { return invalid(); @@ -78,6 +91,7 @@ function requireRecord(value: unknown): Readonly> { return value as Readonly>; } +/** Requires one exact closed set of object fields. */ function requireExactKeys( record: Readonly>, expectedKeys: readonly string[], @@ -92,6 +106,7 @@ function requireExactKeys( } } +/** Requires one trimmed non-empty string within an explicit maximum length. */ function requireString(value: unknown, maximumLength: number): string { if (typeof value !== 'string') { return invalid(); @@ -103,6 +118,7 @@ function requireString(value: unknown, maximumLength: number): string { return normalized; } +/** Requires and canonicalizes one opaque UUIDv4 identifier. */ function requireUuidV4(value: unknown): string { const normalized = requireString(value, 64).toLowerCase(); if (!UUID_V4_PATTERN.test(normalized)) { @@ -111,6 +127,7 @@ function requireUuidV4(value: unknown): string { return normalized; } +/** Requires and canonicalizes one SHA-256 hexadecimal digest. */ function requireDigest(value: unknown): string { const digest = requireString(value, 64).toLowerCase(); if (!SHA_256_PATTERN.test(digest)) { @@ -119,6 +136,7 @@ function requireDigest(value: unknown): string { return digest; } +/** Requires a valid date or RFC 3339 timestamp and normalizes it to UTC. */ function requireTimestamp(value: unknown): string { if (value instanceof Date) { if (Number.isNaN(value.getTime())) { @@ -136,46 +154,16 @@ function requireTimestamp(value: unknown): string { return parsed.toISOString(); } -function validateContextItem(value: ProposalContextItem): ProposalContextItem { - const record = requireRecord(value); - requireExactKeys(record, ['id', 'kind', 'title', 'status']); - const kind = record.kind; - const status = record.status; - if ( - kind !== 'goal' && - kind !== 'project' && - kind !== 'milestone' && - kind !== 'task' && - kind !== 'habit' - ) { - return invalid(); - } - if (status !== 'active' && status !== 'blocked' && status !== 'completed') { - return invalid(); - } - return Object.freeze({ - id: requireUuidV4(record.id), - kind, - title: requireString(record.title, MAXIMUM_TEXT_LENGTH), - status, - }); -} - +/** Revalidates one proposal request and maps generator failures to audit validation. */ function validateRequest(value: unknown): ProposalRequest { try { - const request = validateProposalRequest(value); - return Object.freeze({ - objective: request.objective, - context: Object.freeze(request.context.map(validateContextItem)), - }); - } catch (error) { - if (error instanceof ProposalValidationError) { - return invalid(); - } - throw error; + return validateProposalRequest(value); + } catch { + return invalid(); } } +/** Revalidates one inert proposed operation for immutable evidence. */ function validateOperation(value: unknown): ProposalOperation { const record = requireRecord(value); const hasTargetId = Object.hasOwn(record, 'targetId'); @@ -202,6 +190,7 @@ function validateOperation(value: unknown): ProposalOperation { }); } +/** Revalidates one immutable inert proposal and its bounded nested fields. */ function validateProposal(value: unknown): AuditableProposal { const record = requireRecord(value); requireExactKeys(record, [ @@ -237,6 +226,7 @@ function validateProposal(value: unknown): AuditableProposal { }); } +/** Projects one validated operation into deterministic digest field order. */ function canonicalOperation( operation: ProposalOperation, ): Readonly> { @@ -252,6 +242,7 @@ function canonicalOperation( }; } +/** Computes a lowercase SHA-256 digest over canonical JSON evidence. */ function digest(value: unknown): string { return createHash('sha256').update(JSON.stringify(value)).digest('hex'); } diff --git a/apps/ai-service/src/proposal-service.ts b/apps/ai-service/src/proposal-service.ts index 042e0c96..6702282f 100644 --- a/apps/ai-service/src/proposal-service.ts +++ b/apps/ai-service/src/proposal-service.ts @@ -50,24 +50,30 @@ export interface ProposalModelDraft { /** Read-only model boundary. It receives evidence and returns suggestions only. */ export interface ProposalModel { + /** Produces one untrusted structured suggestion from validated read-only evidence. */ generate(input: ProposalRequest): Promise; } +/** Supplies deterministic proposal creation time in tests and production. */ export type ProposalClock = () => Date; +/** Supplies opaque UUIDv4 proposal identifiers. */ export type ProposalIdFactory = () => string; /** Stable validation failure suitable for bounded HTTP error mapping. */ export class ProposalValidationError extends Error { + /** Creates a stable credential-free validation failure. */ constructor() { super('Proposal request or model output is invalid'); this.name = 'ProposalValidationError'; } } +/** Raises the shared bounded proposal validation failure. */ function invalid(): never { throw new ProposalValidationError(); } +/** Requires one trimmed non-empty string within an explicit maximum length. */ function requireString(value: unknown, maximumLength: number): string { if (typeof value !== 'string') { return invalid(); @@ -79,6 +85,7 @@ function requireString(value: unknown, maximumLength: number): string { return normalized; } +/** Requires and canonicalizes one opaque UUIDv4 identifier. */ function requireUuidV4(value: unknown): string { const normalized = requireString(value, 64).toLowerCase(); if (!UUID_V4_PATTERN.test(normalized)) { @@ -87,6 +94,7 @@ function requireUuidV4(value: unknown): string { return normalized; } +/** Requires an object-shaped untrusted value. */ function requireRecord(value: unknown): Readonly> { if (typeof value !== 'object' || value === null || Array.isArray(value)) { return invalid(); @@ -94,6 +102,7 @@ function requireRecord(value: unknown): Readonly> { return value as Readonly>; } +/** Rejects missing, unknown, or duplicate object fields through an exact key set. */ function requireExactKeys( record: Readonly>, expectedKeys: readonly string[], @@ -108,6 +117,7 @@ function requireExactKeys( } } +/** Validates one read-only planning evidence item. */ function requireContextItem(value: unknown): ProposalContextItem { const record = requireRecord(value); requireExactKeys(record, ['id', 'kind', 'title', 'status']); @@ -150,6 +160,7 @@ export function validateProposalRequest(value: unknown): ProposalRequest { }); } +/** Validates a bounded non-empty rationale collection. */ function validateRationale(value: unknown): readonly string[] { if ( !Array.isArray(value) || @@ -163,6 +174,7 @@ function validateRationale(value: unknown): readonly string[] { ); } +/** Validates one inert user-confirmable proposed operation. */ function validateOperation(value: unknown): ProposalOperation { const record = requireRecord(value); const hasTargetId = Object.hasOwn(record, 'targetId'); @@ -189,6 +201,7 @@ function validateOperation(value: unknown): ProposalOperation { }); } +/** Validates a bounded non-empty operation collection. */ function validateOperations(value: unknown): readonly ProposalOperation[] { if ( !Array.isArray(value) || @@ -200,15 +213,13 @@ function validateOperations(value: unknown): readonly ProposalOperation[] { return Object.freeze(value.map(validateOperation)); } +/** Interpolates untrusted text into a fixed-size model response without overflow. */ function boundedInterpolation( prefix: string, value: string, suffix: string, ): string { const available = MAXIMUM_TEXT_LENGTH - prefix.length - suffix.length; - if (available < TRUNCATION_MARKER.length) { - return invalid(); - } const boundedValue = value.length <= available ? value @@ -218,6 +229,7 @@ function boundedInterpolation( /** A deterministic local adapter used until a bounded external model is wired. */ export class RuleBasedProposalModel implements ProposalModel { + /** Produces one deterministic inert proposal draft from validated evidence. */ async generate(input: ProposalRequest): Promise { const actionable = input.context.find( (item) => item.status !== 'completed', @@ -268,12 +280,14 @@ export class RuleBasedProposalModel implements ProposalModel { /** Generates inert proposals without receiving any write-capable dependency. */ export class ProposalService { + /** Creates the generator with explicit model, clock, and identifier seams. */ constructor( private readonly model: ProposalModel, private readonly clock: ProposalClock = () => new Date(), private readonly idFactory: ProposalIdFactory = randomUUID, ) {} + /** Validates input and model output before returning one immutable inert proposal. */ async generateProposal( workspaceId: string, request: ProposalRequest, diff --git a/apps/ai-service/src/quality-coverage.test.ts b/apps/ai-service/src/quality-coverage.test.ts new file mode 100644 index 00000000..4c7a92b1 --- /dev/null +++ b/apps/ai-service/src/quality-coverage.test.ts @@ -0,0 +1,931 @@ +import { HttpException, Logger } from '@nestjs/common'; +import { NestFactory } from '@nestjs/core'; +import { describe, expect, it, vi } from 'vitest'; +import { + type AiBootstrapApplication, + AiProposalAuditController, + AiProposalController, + bootstrapAiService, + createAiApplication, + resolveAiServicePort, +} from './main'; +import { + ProposalAuditApplication, + ProposalAuditNotFoundError, + validateProposalDecisionRequest, +} from './proposal-audit-application'; +import { + computeProposalContentDigest, + computeProposalRequestDigest, + createProposalAuditRecord, + createProposalDecisionEvent, + type ProposalAuditRecord, + ProposalAuditValidationError, + ProposalDecisionEvent, + ProposalDigestMismatchError, + validateProposalAuditRecord, + validateProposalDecisionEvent, +} from './proposal-audit-domain'; +import { + type ProposalAuditSqlClient, + type ProposalAuditSqlQueryResult, + ProposalAuditPersistenceError, + ProposalDecisionConflictError, + PostgresProposalAuditRepository, +} from './postgres-proposal-audit-repository'; +import { + type AuditableProposal, + type ProposalModel, + type ProposalModelDraft, + type ProposalRequest, + ProposalService, + ProposalValidationError, + RuleBasedProposalModel, + validateProposalRequest, +} from './proposal-service'; + +const WORKSPACE_ID = '11111111-1111-4111-8111-111111111111'; +const OTHER_WORKSPACE_ID = 'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa'; +const PROPOSAL_ID = '22222222-2222-4222-8222-222222222222'; +const TASK_ID = '33333333-3333-4333-8333-333333333333'; +const ACTOR_ID = '44444444-4444-4444-8444-444444444444'; +const EVENT_ID = '55555555-5555-4555-8555-555555555555'; +const IDEMPOTENCY_KEY = '66666666-6666-4666-8666-666666666666'; +const OTHER_EVENT_ID = '77777777-7777-4777-8777-777777777777'; +const OTHER_ACTOR_ID = '88888888-8888-4888-8888-888888888888'; + +function request(overrides: Partial = {}): ProposalRequest { + return { + objective: 'Ship a reviewable increment', + context: [ + { + id: TASK_ID, + kind: 'task', + title: 'Verify the release candidate', + status: 'active', + }, + ], + ...overrides, + }; +} + +function proposal( + overrides: Partial = {}, +): AuditableProposal { + return { + proposalId: PROPOSAL_ID, + workspaceId: WORKSPACE_ID, + summary: 'Prioritize release verification.', + rationale: ['The release candidate is the active critical path.'], + operations: [ + { + kind: 'prioritize_item', + targetId: TASK_ID, + description: 'Prioritize release verification for explicit review.', + }, + ], + requiresConfirmation: true, + createdAt: '2026-08-04T00:00:00.000Z', + ...overrides, + }; +} + +function auditRecord( + proposalOverrides: Partial = {}, +): ProposalAuditRecord { + return createProposalAuditRecord({ + proposal: proposal(proposalOverrides), + request: request(), + modelId: 'rule-based-v1', + recordedAt: '2026-08-04T00:00:01.000Z', + }); +} + +function decisionEvent( + overrides: Partial = {}, +): ProposalDecisionEvent { + const audit = auditRecord(); + return createProposalDecisionEvent({ + id: overrides.id ?? EVENT_ID, + workspaceId: overrides.workspaceId ?? WORKSPACE_ID, + proposalId: overrides.proposalId ?? PROPOSAL_ID, + proposalContentDigest: + overrides.proposalContentDigest ?? audit.contentDigest, + actorId: overrides.actorId ?? ACTOR_ID, + decision: overrides.decision ?? 'accepted', + ...(overrides.reason === undefined ? {} : { reason: overrides.reason }), + idempotencyKey: overrides.idempotencyKey ?? IDEMPOTENCY_KEY, + decidedAt: overrides.decidedAt ?? '2026-08-04T00:00:02.000Z', + recordedAt: overrides.recordedAt ?? '2026-08-04T00:00:03.000Z', + }); +} + +function proposalRow(overrides: Record = {}) { + const audit = auditRecord(); + return { + proposal_id: audit.proposal.proposalId, + workspace_id: audit.proposal.workspaceId, + model_id: audit.modelId, + request_json: audit.request, + request_digest: audit.requestDigest, + summary: audit.proposal.summary, + rationale_json: audit.proposal.rationale, + operations_json: audit.proposal.operations, + requires_confirmation: true, + content_digest: audit.contentDigest, + created_at: new Date(audit.proposal.createdAt), + recorded_at: new Date(audit.recordedAt), + ...overrides, + }; +} + +function decisionRow(overrides: Record = {}) { + const event = decisionEvent(); + return { + id: event.id, + workspace_id: event.workspaceId, + proposal_id: event.proposalId, + proposal_content_digest: event.proposalContentDigest, + actor_id: event.actorId, + decision_kind: event.decision, + reason_text: event.reason ?? null, + idempotency_key: event.idempotencyKey, + decided_at: new Date(event.decidedAt), + recorded_at: new Date(event.recordedAt), + ...overrides, + }; +} + +interface ErrorResponse { + readonly error: unknown; +} + +type SqlResponse = unknown[] | ErrorResponse; + +class SequencedSqlClient implements ProposalAuditSqlClient { + readonly calls: Array<{ text: string; values: readonly unknown[] }> = []; + private readonly responses: SqlResponse[]; + + constructor(...responses: SqlResponse[]) { + this.responses = [...responses]; + } + + async query( + text: string, + values: readonly unknown[], + ): Promise> { + this.calls.push({ text, values }); + const response = this.responses.shift() ?? []; + if (!Array.isArray(response)) { + throw response.error; + } + return { rows: [...response] as Row[] }; + } +} + +function staticModel(draft: ProposalModelDraft): ProposalModel { + return { + async generate(): Promise { + return draft; + }, + }; +} + +async function expectProblem( + promise: Promise, + status: number, + code: string, +): Promise { + try { + await promise; + } catch (error) { + expect(error).toBeInstanceOf(HttpException); + const exception = error as HttpException; + expect(exception.getStatus()).toBe(status); + expect(exception.getResponse()).toMatchObject({ status, code }); + return; + } + throw new Error(`Expected HTTP problem ${status}/${code}`); +} + +function throwingApplication(error: unknown): ProposalAuditApplication { + const fail = async (): Promise => { + throw error; + }; + return { + generateProposal: fail, + listProposals: fail, + findProposal: fail, + listDecisions: fail, + appendDecision: fail, + } as unknown as ProposalAuditApplication; +} + +describe('proposal service exhaustive boundary evidence', () => { + it('accepts every supported context kind and status', () => { + const kinds = ['goal', 'project', 'milestone', 'task', 'habit'] as const; + const statuses = ['active', 'blocked', 'completed'] as const; + for (const kind of kinds) { + for (const status of statuses) { + expect( + validateProposalRequest({ + objective: 'Review every supported branch', + context: [ + { id: TASK_ID, kind, title: `${kind}-${status}`, status }, + ], + }).context[0], + ).toMatchObject({ kind, status }); + } + } + }); + + it.each([ + null, + [], + 42, + { objective: 'x', different: [] }, + { objective: 'x', context: 'not-an-array' }, + { objective: 'x', context: Array.from({ length: 201 }, () => ({})) }, + { objective: 42, context: [] }, + { objective: ' ', context: [] }, + { objective: 'x'.repeat(2_001), context: [] }, + { + objective: 'x', + context: [{ id: TASK_ID, kind: 'unknown', title: 'x', status: 'active' }], + }, + { + objective: 'x', + context: [{ id: TASK_ID, kind: 'task', title: 'x', status: 'unknown' }], + }, + { + objective: 'x', + context: [{ id: TASK_ID, kind: 'task', title: 42, status: 'active' }], + }, + { + objective: 'x', + context: [{ id: TASK_ID, kind: 'task', title: ' ', status: 'active' }], + }, + { + objective: 'x', + context: [ + { + id: TASK_ID, + kind: 'task', + title: 'x'.repeat(1_001), + status: 'active', + }, + ], + }, + { + objective: 'x', + context: [{ id: 42, kind: 'task', title: 'x', status: 'active' }], + }, + ])('rejects malformed proposal request %#', (value) => { + expect(() => validateProposalRequest(value)).toThrow( + ProposalValidationError, + ); + }); + + it('validates every operation shape and rejects malformed model output', async () => { + const validDraft: ProposalModelDraft = { + summary: 'Valid summary', + rationale: ['Valid rationale'], + operations: [ + { kind: 'create_task', description: 'Create a task' }, + { + kind: 'prioritize_item', + description: 'Prioritize a task', + targetId: TASK_ID, + }, + { + kind: 'schedule_item', + description: 'Schedule a task', + targetId: TASK_ID, + }, + ], + }; + await expect( + new ProposalService( + staticModel(validDraft), + () => new Date('2026-08-04T00:00:00.000Z'), + () => PROPOSAL_ID, + ).generateProposal(WORKSPACE_ID, request()), + ).resolves.toMatchObject({ operations: validDraft.operations }); + + const invalidDrafts: ProposalModelDraft[] = [ + { ...validDraft, summary: 42 }, + { ...validDraft, summary: ' ' }, + { ...validDraft, summary: 'x'.repeat(1_001) }, + { ...validDraft, rationale: 'not-an-array' }, + { ...validDraft, rationale: [] }, + { ...validDraft, rationale: Array.from({ length: 21 }, () => 'x') }, + { ...validDraft, rationale: [42] }, + { ...validDraft, operations: 'not-an-array' }, + { ...validDraft, operations: [] }, + { + ...validDraft, + operations: Array.from({ length: 21 }, () => ({ + kind: 'create_task', + description: 'x', + })), + }, + { + ...validDraft, + operations: [{ kind: 'delete_item', description: 'x' }], + }, + { + ...validDraft, + operations: [{ kind: 'create_task', targetId: TASK_ID }], + }, + { + ...validDraft, + operations: [{ kind: 'create_task', description: 42 }], + }, + { + ...validDraft, + operations: [ + { kind: 'prioritize_item', description: 'x', targetId: 'invalid' }, + ], + }, + ]; + for (const draft of invalidDrafts) { + await expect( + new ProposalService(staticModel(draft)).generateProposal( + WORKSPACE_ID, + request(), + ), + ).rejects.toBeInstanceOf(ProposalValidationError); + } + }); + + it('rejects invalid clock and identifier factories', async () => { + await expect( + new ProposalService( + new RuleBasedProposalModel(), + () => new Date(Number.NaN), + ).generateProposal(WORKSPACE_ID, request()), + ).rejects.toBeInstanceOf(ProposalValidationError); + await expect( + new ProposalService( + new RuleBasedProposalModel(), + () => new Date('2026-08-04T00:00:00.000Z'), + () => 'invalid', + ).generateProposal(WORKSPACE_ID, request()), + ).rejects.toBeInstanceOf(ProposalValidationError); + }); +}); + +describe('proposal audit domain exhaustive evidence', () => { + it('canonicalizes operations with and without targets and accepts Date rows', () => { + const noTarget = proposal({ + operations: [{ kind: 'create_task', description: 'Create the task' }], + createdAt: new Date('2026-08-04T00:00:00.000Z') as unknown as string, + }); + const requestDigest = computeProposalRequestDigest(WORKSPACE_ID, request()); + expect( + computeProposalContentDigest(noTarget, 'rule-based-v1', requestDigest), + ).toMatch(/^[0-9a-f]{64}$/); + expect( + createProposalAuditRecord({ + proposal: noTarget, + request: request(), + modelId: 'rule-based-v1', + recordedAt: new Date('2026-08-04T00:00:01.000Z') as unknown as string, + }), + ).toMatchObject({ + proposal: { createdAt: '2026-08-04T00:00:00.000Z' }, + recordedAt: '2026-08-04T00:00:01.000Z', + }); + }); + + it.each([null, [], 42, { other: 'x', context: [] }])( + 'rejects malformed audit requests %#', + (value) => { + expect(() => + computeProposalRequestDigest( + WORKSPACE_ID, + value as unknown as ProposalRequest, + ), + ).toThrow(ProposalAuditValidationError); + }, + ); + + it('rejects every malformed proposal evidence family', () => { + const digest = computeProposalRequestDigest(WORKSPACE_ID, request()); + const invalidProposals: unknown[] = [ + null, + [], + { ...proposal(), createdAt: undefined, other: 'x' }, + { ...proposal(), rationale: 'not-an-array' }, + { ...proposal(), rationale: [] }, + { ...proposal(), rationale: Array.from({ length: 21 }, () => 'x') }, + { ...proposal(), operations: 'not-an-array' }, + { ...proposal(), operations: [] }, + { + ...proposal(), + operations: Array.from({ length: 21 }, () => ({ + kind: 'create_task', + description: 'x', + })), + }, + { ...proposal(), requiresConfirmation: false }, + { ...proposal(), proposalId: 42 }, + { ...proposal(), workspaceId: 'invalid' }, + { ...proposal(), summary: 42 }, + { ...proposal(), summary: ' ' }, + { ...proposal(), summary: 'x'.repeat(1_001) }, + { ...proposal(), rationale: [42] }, + { ...proposal(), operations: [null] }, + { + ...proposal(), + operations: [{ kind: 'create_task', targetId: TASK_ID }], + }, + { + ...proposal(), + operations: [{ kind: 'delete_item', description: 'x' }], + }, + { + ...proposal(), + operations: [{ kind: 'create_task', description: 42 }], + }, + { + ...proposal(), + operations: [ + { kind: 'schedule_item', description: 'x', targetId: 'invalid' }, + ], + }, + { ...proposal(), createdAt: new Date(Number.NaN) }, + { ...proposal(), createdAt: 42 }, + { ...proposal(), createdAt: 'tomorrow' }, + { ...proposal(), createdAt: '2026-13-01T00:00:00Z' }, + ]; + for (const value of invalidProposals) { + expect(() => + computeProposalContentDigest( + value as AuditableProposal, + 'rule-based-v1', + digest, + ), + ).toThrow(ProposalAuditValidationError); + } + for (const modelId of [42, ' ', 'x'.repeat(201)]) { + expect(() => + computeProposalContentDigest(proposal(), modelId as string, digest), + ).toThrow(ProposalAuditValidationError); + } + for (const value of [42, 'invalid']) { + expect(() => + computeProposalContentDigest( + proposal(), + 'rule-based-v1', + value as string, + ), + ).toThrow(ProposalAuditValidationError); + } + }); + + it('rejects malformed audit records and decision events at every timestamp branch', () => { + const audit = auditRecord(); + const invalidAuditValues: unknown[] = [ + null, + [], + { ...audit, recordedAt: undefined, other: 'x' }, + { ...audit, requestDigest: 'invalid' }, + { ...audit, contentDigest: '0'.repeat(64) }, + { ...audit, recordedAt: new Date(Number.NaN) }, + { ...audit, recordedAt: 42 }, + { ...audit, recordedAt: 'tomorrow' }, + { ...audit, recordedAt: '2026-13-01T00:00:00Z' }, + ]; + for (const value of invalidAuditValues) { + expect(() => validateProposalAuditRecord(value)).toThrow( + ProposalAuditValidationError, + ); + } + + expect(() => + createProposalDecisionEvent({ + ...decisionEvent(), + decision: 'applied' as 'accepted', + }), + ).toThrow(ProposalAuditValidationError); + expect(() => + createProposalDecisionEvent({ + ...decisionEvent(), + decidedAt: new Date(Number.NaN) as unknown as string, + }), + ).toThrow(ProposalAuditValidationError); + expect( + createProposalDecisionEvent({ + ...decisionEvent(), + decidedAt: new Date('2026-08-04T00:00:02.000Z') as unknown as string, + }), + ).not.toHaveProperty('reason'); + + const invalidDecisionValues: unknown[] = [ + null, + [], + { ...decisionEvent(), recordedAt: undefined, other: 'x' }, + { ...decisionEvent(), decision: 'applied' }, + { ...decisionEvent(), proposalContentDigest: 42 }, + { ...decisionEvent(), reason: 42 }, + { ...decisionEvent(), decidedAt: '2026-13-01T00:00:00Z' }, + ]; + for (const value of invalidDecisionValues) { + expect(() => validateProposalDecisionEvent(value)).toThrow( + ProposalAuditValidationError, + ); + } + }); +}); + +describe('proposal audit application residual validation', () => { + it.each([ + { + expectedContentDigest: 'a'.repeat(64), + idempotencyKey: IDEMPOTENCY_KEY, + decision: 'accepted', + decidedAt: '2026-13-01T00:00:00Z', + }, + { + expectedContentDigest: 'a'.repeat(64), + idempotencyKey: IDEMPOTENCY_KEY, + decision: 'accepted', + reason: 42, + decidedAt: '2026-08-04T00:00:00Z', + }, + ])('rejects semantically invalid decision input %#', (value) => { + expect(() => validateProposalDecisionRequest(value)).toThrow( + ProposalAuditValidationError, + ); + }); + + it('covers non-Date clocks and decisions without a reason', async () => { + const repository = { + records: [auditRecord()], + async saveProposal(): Promise {}, + async findProposal(): Promise { + return this.records[0]; + }, + async listProposals(): Promise { + return this.records; + }, + async appendDecision(event: ProposalDecisionEvent) { + return event; + }, + async listDecisions(): Promise { + return []; + }, + }; + const badClock = new ProposalAuditApplication( + new ProposalService(new RuleBasedProposalModel()), + repository, + 'rule-based-v1', + () => 'not-a-date' as unknown as Date, + ); + await expect( + badClock.generateProposal(WORKSPACE_ID, request()), + ).rejects.toBeInstanceOf(ProposalAuditValidationError); + + const service = new ProposalAuditApplication( + new ProposalService( + new RuleBasedProposalModel(), + () => new Date('2026-08-04T00:00:00Z'), + () => PROPOSAL_ID, + ), + repository, + 'rule-based-v1', + () => new Date('2026-08-04T00:00:01Z'), + () => EVENT_ID, + ); + await expect( + service.appendDecision(WORKSPACE_ID, PROPOSAL_ID, ACTOR_ID, { + expectedContentDigest: repository.records[0]!.contentDigest, + idempotencyKey: IDEMPOTENCY_KEY, + decision: 'rejected', + decidedAt: '2026-08-04T00:00:02Z', + }), + ).resolves.not.toHaveProperty('reason'); + }); +}); + +describe('PostgreSQL proposal audit residual safety branches', () => { + it('rejects invalid string identifiers, duplicate rows, and row identity drift', async () => { + await expect( + new PostgresProposalAuditRepository( + new SequencedSqlClient(), + ).listProposals('invalid'), + ).rejects.toBeInstanceOf(ProposalAuditPersistenceError); + await expect( + new PostgresProposalAuditRepository( + new SequencedSqlClient([proposalRow(), proposalRow()]), + ).findProposal(WORKSPACE_ID, PROPOSAL_ID), + ).rejects.toBeInstanceOf(ProposalAuditPersistenceError); + await expect( + new PostgresProposalAuditRepository( + new SequencedSqlClient([proposalRow({ proposal_id: OTHER_EVENT_ID })]), + ).findProposal(WORKSPACE_ID, PROPOSAL_ID), + ).rejects.toBeInstanceOf(ProposalAuditPersistenceError); + await expect( + new PostgresProposalAuditRepository( + new SequencedSqlClient([]), + ).findProposal(WORKSPACE_ID, PROPOSAL_ID), + ).resolves.toBeUndefined(); + }); + + it('maps malformed inputs, rows, and SQL transport failures', async () => { + await expect( + new PostgresProposalAuditRepository( + new SequencedSqlClient(), + ).saveProposal({} as ProposalAuditRecord), + ).rejects.toBeInstanceOf(ProposalAuditPersistenceError); + await expect( + new PostgresProposalAuditRepository( + new SequencedSqlClient(), + ).appendDecision({} as ProposalDecisionEvent), + ).rejects.toBeInstanceOf(ProposalAuditPersistenceError); + await expect( + new PostgresProposalAuditRepository( + new SequencedSqlClient({ error: new Error('transport detail') }), + ).listProposals(WORKSPACE_ID), + ).rejects.toBeInstanceOf(ProposalAuditPersistenceError); + await expect( + new PostgresProposalAuditRepository( + new SequencedSqlClient([proposalRow({ content_digest: 'invalid' })]), + ).listProposals(WORKSPACE_ID), + ).rejects.toBeInstanceOf(ProposalAuditPersistenceError); + await expect( + new PostgresProposalAuditRepository( + new SequencedSqlClient([decisionRow({ decision_kind: 'applied' })]), + ).listDecisions(WORKSPACE_ID, PROPOSAL_ID), + ).rejects.toBeInstanceOf(ProposalAuditPersistenceError); + }); + + it('requires exactly one inserted or replayed decision row', async () => { + await expect( + new PostgresProposalAuditRepository( + new SequencedSqlClient([]), + ).appendDecision(decisionEvent()), + ).rejects.toBeInstanceOf(ProposalAuditPersistenceError); + + const uniqueError = { + error: { + code: '23505', + constraint: 'proposal_decision_events_idempotency_unique', + }, + }; + await expect( + new PostgresProposalAuditRepository( + new SequencedSqlClient(uniqueError, []), + ).appendDecision(decisionEvent()), + ).rejects.toBeInstanceOf(ProposalAuditPersistenceError); + await expect( + new PostgresProposalAuditRepository( + new SequencedSqlClient(uniqueError, [decisionRow(), decisionRow()]), + ).appendDecision(decisionEvent()), + ).rejects.toBeInstanceOf(ProposalAuditPersistenceError); + }); + + it('validates every persisted decision identity and reason shape', async () => { + const invalidRows = [ + decisionRow({ workspace_id: OTHER_WORKSPACE_ID }), + decisionRow({ proposal_id: OTHER_EVENT_ID }), + decisionRow({ decision_kind: 'applied' }), + ]; + for (const row of invalidRows) { + await expect( + new PostgresProposalAuditRepository( + new SequencedSqlClient([row]), + ).listDecisions(WORKSPACE_ID, PROPOSAL_ID), + ).rejects.toBeInstanceOf(ProposalAuditPersistenceError); + } + + await expect( + new PostgresProposalAuditRepository( + new SequencedSqlClient([ + decisionRow({ idempotency_key: OTHER_EVENT_ID }), + ]), + ).appendDecision(decisionEvent()), + ).rejects.toBeInstanceOf(ProposalAuditPersistenceError); + + await expect( + new PostgresProposalAuditRepository( + new SequencedSqlClient([ + decisionRow({ reason_text: undefined }), + decisionRow({ reason_text: 'Reviewed' }), + ]), + ).listDecisions(WORKSPACE_ID, PROPOSAL_ID), + ).resolves.toEqual([ + decisionEvent(), + decisionEvent({ reason: 'Reviewed' }), + ]); + }); + + it('rejects each non-identical idempotency replay field', async () => { + const uniqueError = { + error: { + code: '23505', + constraint: 'proposal_decision_events_idempotency_unique', + }, + }; + const attempted = decisionEvent({ reason: 'Reviewed' }); + const mismatches = [ + decisionRow({ + proposal_content_digest: 'a'.repeat(64), + reason_text: 'Reviewed', + }), + decisionRow({ actor_id: OTHER_ACTOR_ID, reason_text: 'Reviewed' }), + decisionRow({ decision_kind: 'rejected', reason_text: 'Reviewed' }), + decisionRow({ reason_text: 'Different' }), + decisionRow({ + reason_text: 'Reviewed', + decided_at: new Date('2026-08-04T00:00:04.000Z'), + }), + ]; + for (const row of mismatches) { + await expect( + new PostgresProposalAuditRepository( + new SequencedSqlClient(uniqueError, [row]), + ).appendDecision(attempted), + ).rejects.toBeInstanceOf(ProposalDecisionConflictError); + } + }); + + it('maps primitive and mismatched database errors without leaking details', async () => { + for (const error of [ + 'transport-secret', + { + code: 'XX000', + constraint: 'proposal_decision_events_idempotency_unique', + }, + ]) { + await expect( + new PostgresProposalAuditRepository( + new SequencedSqlClient({ error }), + ).appendDecision(decisionEvent()), + ).rejects.toEqual(new ProposalAuditPersistenceError()); + } + }); +}); + +describe('AI controllers and bootstrap error contracts', () => { + it('covers health, successful generation, and all generation failures', async () => { + const generated = proposal(); + const generator = { + generateProposal: vi.fn().mockResolvedValue(generated), + }; + const controller = new AiProposalController(generator); + expect(controller.health()).toEqual({ + status: 'ok', + service: 'ai-service', + }); + await expect( + controller.createProposal(WORKSPACE_ID, request()), + ).resolves.toEqual(generated); + + await expectProblem( + controller.createProposal(undefined, request()), + 400, + 'invalid_request', + ); + await expectProblem( + controller.createProposal(WORKSPACE_ID, null), + 400, + 'invalid_request', + ); + for (const [error, status, code] of [ + [new ProposalAuditValidationError(), 400, 'invalid_request'], + [new ProposalAuditPersistenceError(), 503, 'audit_unavailable'], + [new Error('secret'), 503, 'proposal_unavailable'], + ['secret', 503, 'proposal_unavailable'], + ] as const) { + await expectProblem( + new AiProposalController({ + async generateProposal(): Promise { + throw error; + }, + }).createProposal(WORKSPACE_ID, request()), + status, + code, + ); + } + }); + + it('covers successful audit calls and missing trusted headers', async () => { + const audit = auditRecord(); + const event = decisionEvent(); + const application = { + listProposals: vi.fn().mockResolvedValue([audit]), + findProposal: vi.fn().mockResolvedValue(audit), + listDecisions: vi.fn().mockResolvedValue([event]), + appendDecision: vi.fn().mockResolvedValue(event), + } as unknown as ProposalAuditApplication; + const controller = new AiProposalAuditController(application); + + await expect(controller.listProposals(WORKSPACE_ID)).resolves.toEqual([ + audit, + ]); + await expect( + controller.findProposal(WORKSPACE_ID, PROPOSAL_ID), + ).resolves.toEqual(audit); + await expect( + controller.listDecisions(WORKSPACE_ID, PROPOSAL_ID), + ).resolves.toEqual([event]); + await expect( + controller.appendDecision(WORKSPACE_ID, ACTOR_ID, PROPOSAL_ID, { + expectedContentDigest: audit.contentDigest, + idempotencyKey: IDEMPOTENCY_KEY, + decision: 'accepted', + decidedAt: '2026-08-04T00:00:02Z', + }), + ).resolves.toEqual(event); + + await expectProblem( + controller.listProposals(undefined), + 400, + 'invalid_request', + ); + await expectProblem( + controller.findProposal(undefined, PROPOSAL_ID), + 400, + 'invalid_request', + ); + await expectProblem( + controller.listDecisions(undefined, PROPOSAL_ID), + 400, + 'invalid_request', + ); + await expectProblem( + controller.appendDecision(undefined, ACTOR_ID, PROPOSAL_ID, {}), + 400, + 'invalid_request', + ); + await expectProblem( + controller.appendDecision(WORKSPACE_ID, undefined, PROPOSAL_ID, {}), + 400, + 'invalid_request', + ); + }); + + it('maps every audit application failure without credential details', async () => { + const logger = vi + .spyOn(Logger.prototype, 'error') + .mockImplementation(() => undefined); + const cases: Array<[unknown, number, string]> = [ + [new ProposalValidationError(), 400, 'invalid_request'], + [new ProposalAuditValidationError(), 400, 'invalid_request'], + [new ProposalAuditNotFoundError(), 404, 'proposal_not_found'], + [new ProposalDigestMismatchError(), 409, 'stale_proposal'], + [new ProposalDecisionConflictError(), 409, 'idempotency_conflict'], + [new ProposalAuditPersistenceError(), 503, 'audit_unavailable'], + [new Error('password=secret'), 503, 'audit_unavailable'], + ['password=secret', 503, 'audit_unavailable'], + ]; + for (const [error, status, code] of cases) { + await expectProblem( + new AiProposalAuditController(throwingApplication(error)).listProposals( + WORKSPACE_ID, + ), + status, + code, + ); + } + expect(JSON.stringify(logger.mock.calls)).not.toContain('password=secret'); + logger.mockRestore(); + }); + + it('validates service ports and boots through an injected application', async () => { + expect(resolveAiServicePort(undefined)).toBe(4_105); + expect(resolveAiServicePort(' ')).toBe(4_105); + expect(resolveAiServicePort('1')).toBe(1); + expect(resolveAiServicePort('65535')).toBe(65_535); + for (const value of ['0', '65536', '1.5', 'not-a-port']) { + expect(() => resolveAiServicePort(value)).toThrow( + 'AI service port is invalid', + ); + } + + const application: AiBootstrapApplication = { + enableShutdownHooks: vi.fn(), + listen: vi.fn().mockResolvedValue(undefined), + }; + await bootstrapAiService( + { AI_SERVICE_PORT: '4321' }, + async () => application, + ); + expect(application.enableShutdownHooks).toHaveBeenCalledOnce(); + expect(application.listen).toHaveBeenCalledWith(4_321, '0.0.0.0'); + }); + + it('creates the default Nest application through the production module', async () => { + const application: AiBootstrapApplication = { + enableShutdownHooks: vi.fn(), + listen: vi.fn().mockResolvedValue(undefined), + }; + const factory = vi + .spyOn(NestFactory, 'create') + .mockResolvedValue(application as never); + await expect(createAiApplication()).resolves.toBe(application); + factory.mockRestore(); + }); +}); diff --git a/apps/ai-service/src/server.test.ts b/apps/ai-service/src/server.test.ts new file mode 100644 index 00000000..33bab51d --- /dev/null +++ b/apps/ai-service/src/server.test.ts @@ -0,0 +1,14 @@ +import { describe, expect, it, vi } from 'vitest'; + +describe('AI process entrypoint', () => { + it('delegates process startup to the tested bootstrap boundary', async () => { + vi.resetModules(); + const bootstrapAiService = vi.fn().mockResolvedValue(undefined); + vi.doMock('./main', () => ({ bootstrapAiService })); + + await import('./server'); + + expect(bootstrapAiService).toHaveBeenCalledOnce(); + vi.doUnmock('./main'); + }); +}); diff --git a/apps/ai-service/src/server.ts b/apps/ai-service/src/server.ts new file mode 100644 index 00000000..127355f1 --- /dev/null +++ b/apps/ai-service/src/server.ts @@ -0,0 +1,4 @@ +import 'reflect-metadata'; +import { bootstrapAiService } from './main'; + +void bootstrapAiService(); diff --git a/apps/ai-service/vitest.config.ts b/apps/ai-service/vitest.config.ts new file mode 100644 index 00000000..a7439d8b --- /dev/null +++ b/apps/ai-service/vitest.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from 'vitest/config'; + +/** Complete AI-service production coverage gate. */ +export default defineConfig({ + test: { + coverage: { + enabled: true, + provider: 'v8', + reporter: [['text', { maxCols: 1_000 }], 'json', 'json-summary'], + include: ['src/**/*.ts'], + exclude: ['src/**/*.test.ts'], + thresholds: { + statements: 100, + branches: 100, + functions: 100, + lines: 100, + }, + }, + }, +}); diff --git a/apps/notification-service/src/postgres-reminder-repository.integration.test.ts b/apps/notification-service/src/postgres-reminder-repository.integration.test.ts index f04efc91..55067565 100644 --- a/apps/notification-service/src/postgres-reminder-repository.integration.test.ts +++ b/apps/notification-service/src/postgres-reminder-repository.integration.test.ts @@ -303,7 +303,7 @@ describeWithPostgres('PostgreSQL notification repository integration', () => { }); await administrativePool.query( `UPDATE notification_service.reminder_occurrences - SET claim_expires_at = clock_timestamp() - interval '1 second' + SET claim_expires_at = TIMESTAMPTZ '2000-01-01 00:00:00+00' WHERE workspace_id = $1 AND reminder_id = $2`, [workspaceId, reminder.id], ); diff --git a/docs/operations/ai-proposal-audit-assurance.md b/docs/operations/ai-proposal-audit-assurance.md new file mode 100644 index 00000000..59277c19 --- /dev/null +++ b/docs/operations/ai-proposal-audit-assurance.md @@ -0,0 +1,61 @@ +# AI proposal audit assurance + +## Control objective + +The AI service generates inert proposals, records immutable provenance before response, and appends explicit accept or reject decisions without receiving any capability to execute the proposed operations. The service can run independently or behind the LifeOS gateway through the same bounded HTTP and PostgreSQL contracts. + +## Implemented assurance boundary + +- Proposal requests, model drafts, identifiers, timestamps, and persisted rows are revalidated at their trust boundaries. +- Canonical SHA-256 request and content digests bind each proposal to its workspace, model identifier, evidence, output, and creation time. +- `ai.proposal_audit_records` and `ai.proposal_decision_events` are append-only PostgreSQL objects with multi-word `snake_case` identifiers. +- Decision writes require the exact immutable proposal content digest and a UUIDv4 idempotency key. Exact replay returns the original event; conflicting replay fails closed. +- Workspace and actor scope arrive only through trusted headers. Public deployment therefore requires an authenticated private gateway that strips caller-supplied ownership headers and derives them from a verified session. +- RFC 9457 problem responses expose stable codes without prompts, stack traces, SQL details, credentials, model output, or another tenant's existence. +- No route, command bus, generic repository, or adapter can apply or execute a proposal. + +## Human authorization separation + +`requiresConfirmation: true` is an explicit product invariant, not an execution permission. An accepted decision is audit evidence only. A future execution capability must be separately designed, authenticated, authorized, idempotent, reviewable, and connected to bounded domain commands. It must never infer execution authority from the mere presence of an accepted decision. + +## Executable quality evidence + +`apps/ai-service/vitest.config.ts` requires 100% statements, branches, functions, and lines across all production TypeScript. No production file or branch is excluded. `src/docstring-coverage.test.ts` uses the TypeScript compiler API to require JSDoc on production top-level declarations and class/interface members while excluding tests and nested callbacks. + +The test suite includes deterministic unit evidence and real disposable-PostgreSQL/HTTP scenarios for restart durability, tenant isolation, exact decision replay, conflicting replay, stale revisions, append-only enforcement, lifecycle shutdown, pool failures, malformed rows, sanitized errors, and absence of execution routes. + +Run the package assurance gate with: + +```bash +AI_DATABASE_URL=postgresql://... \ +AI_TEST_DATABASE_URL=postgresql://... \ +pnpm --filter @life-os/ai-service test +``` + +The integration database must be disposable and its database name must contain `test`. The suite refuses to drop the `ai` schema otherwise. + +## Continuous risk review triggers + +Re-run architecture, security, privacy, evaluation, and operational review whenever any of the following changes: + +- model or model-provider version; +- system prompt, rubric, tool schema, or output schema; +- evidence source, retrieval policy, or retention period; +- proposal operation vocabulary; +- authenticated gateway or ownership derivation; +- decision policy or future execution permission; +- telemetry attributes, incident response, or production deployment topology. + +## Limitations + +Append-only provenance improves traceability but does not prove model correctness, calibration, fairness, usefulness, copyright compliance, privacy compliance, or freedom from prompt injection. This slice uses the deterministic local rule-based adapter and therefore does not exercise NVIDIA NIM or any external model. External-model introduction requires provider-specific accuracy, robustness, privacy, cost, latency, and adversarial tests before release. + +## References + +Autio, C., Schwartz, R., Dunietz, J., Jain, S., Stanley, M., Tabassi, E., Hall, P., & Roberts, K. (2024). _Artificial intelligence risk management framework: Generative artificial intelligence profile_ (NIST AI 600-1). National Institute of Standards and Technology. https://doi.org/10.6028/NIST.AI.600-1 + +International Organization for Standardization. (2023a). _Information technology—Artificial intelligence—Guidance on risk management_ (ISO/IEC 23894:2023). ISO. + +International Organization for Standardization. (2023b). _Information technology—Artificial intelligence—Management system_ (ISO/IEC 42001:2023). ISO. + +Nottingham, M., Wilde, E., & Dalal, S. (2023). _Problem details for HTTP APIs_ (RFC 9457). RFC Editor. https://doi.org/10.17487/RFC9457 diff --git a/docs/superpowers/plans/2026-08-04-ai-service-quality-gates.md b/docs/superpowers/plans/2026-08-04-ai-service-quality-gates.md new file mode 100644 index 00000000..d9674adf --- /dev/null +++ b/docs/superpowers/plans/2026-08-04-ai-service-quality-gates.md @@ -0,0 +1,292 @@ +# AI Service Quality Gates Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Enforce 100% executable documentation and code coverage for the production AI proposal-audit service while correcting the remaining domain-layer dependency and recording current governance standards. + +**Architecture:** Keep `apps/ai-service` independently deployable. Add package-local Vitest/V8 and TypeScript-AST documentation gates, move stale-revision semantics into the audit domain with a compatibility re-export from the PostgreSQL adapter, then add only realistic tests needed to exercise every production path. Record the assurance boundary in operator documentation and the commercial-readiness manifest. + +**Tech Stack:** TypeScript 5.9, NestJS 11, Vitest 3.2, `@vitest/coverage-v8`, TypeScript compiler API, PostgreSQL 16, pnpm/Turborepo, GitHub Actions. + +## Global Constraints + +- Production coverage thresholds are exactly 100% for statements, branches, functions, and lines. +- No production source file or branch may be excluded from coverage. +- JSDoc applies to production top-level declarations and class/interface members, not test files or nested callbacks. +- Database object identifiers remain multi-word `snake_case`. +- The AI service receives no generic user-data mutation dependency. +- Standards references use APA 7th formatting. +- The exact PR head must pass CI, AppGuardrail, Semgrep, Security Scan, Commercial Readiness, CodeRabbit, and all actionable review threads. + +--- + +### Task 1: Add executable 100% coverage and JSDoc gates + +**Files:** + +- Create: `apps/ai-service/vitest.config.ts` +- Create: `apps/ai-service/src/docstring-coverage.test.ts` +- Modify: `apps/ai-service/package.json` +- Modify: `package.json` + +**Interfaces:** + +- Produces: package-local Vitest configuration with exact 100% thresholds. +- Produces: a deterministic TypeScript-AST documentation test over production declarations. + +- [ ] **Step 1: Add the package-local coverage configuration** + +```ts +import { defineConfig } from 'vitest/config'; + +/** Complete AI-service production coverage gate. */ +export default defineConfig({ + test: { + coverage: { + enabled: true, + provider: 'v8', + reporter: [['text', { maxCols: 1_000 }], 'json-summary'], + include: ['src/**/*.ts'], + exclude: ['src/**/*.test.ts'], + thresholds: { + statements: 100, + branches: 100, + functions: 100, + lines: 100, + }, + }, + }, +}); +``` + +- [ ] **Step 2: Add the failing production-docstring contract** + +Use the TypeScript compiler API to collect undocumented top-level functions, classes, interfaces, type aliases, callable variables, constructors, methods, method signatures, and callable class/interface properties. Exclude `*.test.ts` and nested expression declarations. Assert the resulting list equals `[]`. + +- [ ] **Step 3: Update the AI package scripts and dependencies** + +```json +{ + "scripts": { + "lint": "tsc --noEmit && prettier --single-quote --check package.json tsconfig.json vitest.config.ts \"src/**/*.ts\" ../../docs/operations/ai-proposal-audit-assurance.md ../../docs/superpowers/specs/2026-08-04-ai-service-quality-gates-design.md ../../docs/superpowers/plans/2026-08-04-ai-service-quality-gates.md", + "test": "vitest run --no-file-parallelism --coverage" + }, + "devDependencies": { + "@vitest/coverage-v8": "^3.2.4" + } +} +``` + +- [ ] **Step 4: Add the new deterministic paths to the root formatting gate** + +Append the AI Vitest config, JSDoc test, operator note, design, and plan paths to `format:check` without broadening the repository-wide scope in this slice. + +- [ ] **Step 5: Run the AI gate and capture the expected failures** + +Run: `pnpm --filter @life-os/ai-service test` + +Expected: FAIL with exact uncovered production lines/branches and any undocumented declarations; no configuration or missing-provider error. + +- [ ] **Step 6: Commit the gate before repairing coverage** + +```bash +git add apps/ai-service/package.json apps/ai-service/vitest.config.ts apps/ai-service/src/docstring-coverage.test.ts package.json +git commit -m "test(ai): enforce complete coverage and documentation" +``` + +### Task 2: Restore domain-layer ownership of stale proposal revisions + +**Files:** + +- Modify: `apps/ai-service/src/proposal-audit-domain.ts` +- Modify: `apps/ai-service/src/postgres-proposal-audit-repository.ts` +- Modify: `apps/ai-service/src/proposal-audit-application.ts` +- Modify: `apps/ai-service/src/main.ts` +- Test: `apps/ai-service/src/proposal-audit-domain.test.ts` +- Test: `apps/ai-service/src/postgres-proposal-audit-repository.test.ts` + +**Interfaces:** + +- Produces: `ProposalDigestMismatchError` from `proposal-audit-domain.ts`. +- Preserves: `ProposalDigestMismatchError` re-export from `postgres-proposal-audit-repository.ts`. + +- [ ] **Step 1: Add a failing domain-ownership test** + +```ts +it('owns stale immutable revision semantics in the audit domain', () => { + const error = new ProposalDigestMismatchError(); + expect(error).toMatchObject({ + name: 'ProposalDigestMismatchError', + message: 'Proposal content digest does not match persisted evidence', + }); +}); +``` + +- [ ] **Step 2: Move the error class into the domain** + +```ts +/** Raised when a decision references a stale or unknown proposal digest. */ +export class ProposalDigestMismatchError extends Error { + constructor() { + super('Proposal content digest does not match persisted evidence'); + this.name = 'ProposalDigestMismatchError'; + } +} +``` + +- [ ] **Step 3: Preserve repository compatibility** + +Import the domain error into `postgres-proposal-audit-repository.ts` and add: + +```ts +export { ProposalDigestMismatchError } from './proposal-audit-domain'; +``` + +Remove the repository-local class definition. Update application and HTTP imports to point at the domain module. + +- [ ] **Step 4: Run focused tests** + +Run: `pnpm --filter @life-os/ai-service exec vitest run src/proposal-audit-domain.test.ts src/postgres-proposal-audit-repository.test.ts src/proposal-audit-application.test.ts --no-file-parallelism --coverage.enabled=false` + +Expected: PASS. + +- [ ] **Step 5: Commit the dependency correction** + +```bash +git add apps/ai-service/src/proposal-audit-domain.ts apps/ai-service/src/proposal-audit-domain.test.ts apps/ai-service/src/postgres-proposal-audit-repository.ts apps/ai-service/src/proposal-audit-application.ts apps/ai-service/src/main.ts +git commit -m "refactor(ai): own stale revision semantics in domain" +``` + +### Task 3: Close every production coverage and documentation gap + +**Files:** + +- Modify tests under: `apps/ai-service/src/**/*.test.ts` +- Modify production JSDoc only where the executable contract identifies a missing declaration. + +**Interfaces:** + +- Consumes: exact coverage summary and undocumented-declaration list from Task 1. +- Produces: 100% statements, branches, functions, and lines with no production exclusions. + +- [ ] **Step 1: Run the complete AI suite** + +Run: `pnpm --filter @life-os/ai-service test` + +Expected: FAIL only for concrete coverage/docstring gaps. + +- [ ] **Step 2: Add realistic tests for each reported path** + +Use existing deterministic seams and disposable PostgreSQL integration setup. Required scenarios include invalid clock values, malformed persistence rows, extra SQL rows, unknown error sanitization, pool shutdown concurrency/retry, stale decision digest, conflicting idempotency replay, tenant isolation, and unsupported apply/execute routes. + +- [ ] **Step 3: Re-run until the coverage table is exact** + +Run: `pnpm --filter @life-os/ai-service test` + +Expected terminal table: + +```text +All files | 100 | 100 | 100 | 100 +``` + +- [ ] **Step 4: Run lint, typecheck, and build** + +```bash +pnpm --filter @life-os/ai-service lint +pnpm --filter @life-os/ai-service typecheck +pnpm --filter @life-os/ai-service build +``` + +Expected: all commands exit 0. + +- [ ] **Step 5: Commit complete evidence** + +```bash +git add apps/ai-service/src apps/ai-service/package.json apps/ai-service/vitest.config.ts +git commit -m "test(ai): reach complete production coverage" +``` + +### Task 4: Record governance standards and commercial evidence + +**Files:** + +- Create: `docs/operations/ai-proposal-audit-assurance.md` +- Modify: `product/capabilities.json` +- Modify: `CHANGELOG.md` + +**Interfaces:** + +- Produces: operator-facing control/limitation documentation with APA 7th references. +- Produces: `quality.ai-audit-assurance` commercial-readiness capability. + +- [ ] **Step 1: Write the operator assurance note** + +Document the inert proposal boundary, append-only evidence, human authorization separation, trusted-header assumption, failure sanitization, risk-review triggers, retention limitations, and exact verification commands. + +- [ ] **Step 2: Add APA 7th references** + +Use these exact entries: + +```text +Autio, C., Schwartz, R., Dunietz, J., Jain, S., Stanley, M., Tabassi, E., Hall, P., & Roberts, K. (2024). Artificial intelligence risk management framework: Generative artificial intelligence profile (NIST AI 600-1). National Institute of Standards and Technology. https://doi.org/10.6028/NIST.AI.600-1 + +International Organization for Standardization. (2023a). Information technology—Artificial intelligence—Guidance on risk management (ISO/IEC 23894:2023). ISO. + +International Organization for Standardization. (2023b). Information technology—Artificial intelligence—Management system (ISO/IEC 42001:2023). ISO. + +Nottingham, M., Wilde, E., & Dalal, S. (2023). Problem details for HTTP APIs (RFC 9457). RFC Editor. https://doi.org/10.17487/RFC9457 +``` + +- [ ] **Step 3: Add the capability manifest entry** + +Create `quality.ai-audit-assurance` with dependencies on `ai.auditable-proposals` and `automation.commercial-readiness-loop`; require implementation evidence, `vitest.config.ts`, `docstring-coverage.test.ts`, and the operator note for production maturity. Set `tracking_issue` to `107`. + +- [ ] **Step 4: Update the changelog** + +Under `Unreleased`, record the exact 100% AI-service coverage/JSDoc gate, the domain dependency correction, and governance-assurance documentation. + +- [ ] **Step 5: Run commercial-readiness package tests** + +Run: `pnpm --filter @life-os/commercial-readiness test` + +Expected: PASS with the updated capability graph and no duplicate/unknown dependency. + +- [ ] **Step 6: Commit documentation and evidence** + +```bash +git add docs/operations/ai-proposal-audit-assurance.md product/capabilities.json CHANGELOG.md +git commit -m "docs(ai): record audit assurance standards" +``` + +### Task 5: Verify the exact head and open the PR + +**Files:** + +- No new source files beyond Tasks 1–4. + +**Interfaces:** + +- Produces: one reviewable PR that closes #107. + +- [ ] **Step 1: Run complete local verification** + +```bash +pnpm format:check +pnpm lint +pnpm typecheck +pnpm test +pnpm build +docker compose config --quiet +``` + +Expected: every command exits 0 and AI-service coverage reports 100/100/100/100. + +- [ ] **Step 2: Push and open a non-draft PR** + +Title: `test(ai): enforce complete audit assurance gates` + +Body must summarize the exact coverage results, executable documentation contract, domain-layer correction, standards references, and deferred model-quality/execution scope. Include `Closes #107`. + +- [ ] **Step 3: Drain review feedback** + +For every exact head: inspect CodeRabbit/security/human review, fix still-valid findings, re-run all required workflows, resolve every actionable thread, and merge only when all required workflows plus CodeRabbit are successful. diff --git a/docs/superpowers/specs/2026-08-04-ai-service-quality-gates-design.md b/docs/superpowers/specs/2026-08-04-ai-service-quality-gates-design.md new file mode 100644 index 00000000..c61ad896 --- /dev/null +++ b/docs/superpowers/specs/2026-08-04-ai-service-quality-gates-design.md @@ -0,0 +1,96 @@ +# AI service documentation and 100% coverage design + +**Date:** 2026-08-04 +**Status:** Approved under the autonomous commercial-readiness mandate +**Tracking issue:** #107 + +## Product objective + +The production AI proposal-audit boundary must be reviewable by an acquirer without relying on undocumented behavior or optimistic test claims. Every production declaration is explained, every executable production path is covered, and the operator documentation links the implementation to current authoritative AI-governance and HTTP-error standards. + +This slice does not add an external model, a mutation executor, or a new user-facing workflow. It strengthens the already merged `apps/ai-service` bounded context as an independently deployable service and as a reusable LifeOS module. + +## Bounded-context architecture + +`apps/ai-service` continues to own only inert proposal generation and append-only proposal/decision evidence. It receives no planning, calendar, habit, identity, notification, generic repository, command-bus, event-bus, or user-data mutation dependency. + +The domain layer owns technology-independent proposal and decision semantics. A stale immutable proposal revision is therefore represented by `ProposalDigestMismatchError` in `proposal-audit-domain.ts`. The PostgreSQL repository imports and re-exports that domain error for compatibility, but application code does not depend on the PostgreSQL implementation module. + +All existing database identifiers remain multi-word `snake_case`. This slice creates no new database object. + +## Executable documentation contract + +A dedicated `docstring-coverage.test.ts` parses production TypeScript with the TypeScript compiler API. It requires JSDoc for: + +- top-level functions, classes, interfaces, type aliases, and callable variable declarations; +- constructors, methods, method signatures, and callable properties directly owned by classes or interfaces. + +The contract excludes `*.test.ts` and nested expression declarations. This keeps the gate focused on public behavior and maintainable component boundaries instead of forcing noise comments into local callbacks and fixtures. + +## Complete coverage contract + +`vitest.config.ts` enables V8 coverage with exact thresholds of 100% for statements, branches, functions, and lines. Production files under `src/**/*.ts` are included; test files are excluded. No production source file or branch receives a coverage exemption. + +The AI package test command runs serially with coverage because PostgreSQL integration tests mutate a disposable test schema and deterministic ordering is more valuable than test-process parallelism. `@vitest/coverage-v8` is declared directly by the AI package rather than relying on another workspace package's dependency. + +Coverage failures are resolved through realistic evidence: + +- malformed and oversized input; +- invalid clocks, identifiers, digests, and persisted rows; +- exact idempotent replay and conflicting replay; +- stale proposal revision handling; +- PostgreSQL failure mapping; +- pool error classification and shutdown retry/concurrency; +- unknown error sanitization; +- HTTP tenant isolation and absence of apply/execute routes. + +## Governance and HTTP evidence + +The operator documentation states the implemented control boundary and the limits that remain outside this slice: + +- proposals are inert and require separate human authorization before any future execution; +- immutable proposal content and append-only decisions provide traceability but do not by themselves prove model quality, fairness, or legal compliance; +- tenant and actor headers are trusted only behind a private authenticated gateway; +- RFC 9457 problem responses remain bounded and must not expose stack traces, database details, credentials, prompts, or tenant data; +- risk review is continuous and must be re-run when models, prompts, tools, data sources, or execution permissions change. + +The documentation records APA 7th references to the standards used to justify traceability, risk treatment, lifecycle governance, and sanitized machine-readable errors. + +## Commercial-readiness evidence + +A new capability manifest entry, `quality.ai-audit-assurance`, makes the hourly commercial-readiness loop verify that implementation, 100% coverage configuration, executable documentation, and standards documentation remain present. Documentation alone cannot satisfy production maturity; the production target requires the executable coverage and JSDoc tests. + +## Test and merge gates + +The exact PR head must pass: + +- Prettier formatting; +- TypeScript lint and type checking; +- AI service tests with 100% statement, branch, function, and line coverage; +- complete monorepo tests and build; +- Compose validation; +- AppGuardrail; +- SAST Semgrep; +- Security Scan; +- Commercial Readiness; +- CodeRabbit; +- every actionable review thread. + +## Deferred scope + +- external-model correctness, calibration, and NVIDIA NIM integration; +- prompt-injection and tool-execution policy evaluation; +- model-card, dataset-card, and fairness evaluation automation; +- cross-service OpenTelemetry traces and AI-specific production SLO dashboards; +- separately authorized proposal execution; +- independent human or third-party conformity assessment. + +## References + +Autio, C., Schwartz, R., Dunietz, J., Jain, S., Stanley, M., Tabassi, E., Hall, P., & Roberts, K. (2024). _Artificial intelligence risk management framework: Generative artificial intelligence profile_ (NIST AI 600-1). National Institute of Standards and Technology. https://doi.org/10.6028/NIST.AI.600-1 + +International Organization for Standardization. (2023a). _Information technology—Artificial intelligence—Guidance on risk management_ (ISO/IEC 23894:2023). ISO. + +International Organization for Standardization. (2023b). _Information technology—Artificial intelligence—Management system_ (ISO/IEC 42001:2023). ISO. + +Nottingham, M., Wilde, E., & Dalal, S. (2023). _Problem details for HTTP APIs_ (RFC 9457). RFC Editor. https://doi.org/10.17487/RFC9457 diff --git a/package.json b/package.json index 9877ae60..3e3df415 100644 --- a/package.json +++ b/package.json @@ -13,12 +13,18 @@ "lint": "turbo run lint", "test": "turbo run test", "typecheck": "turbo run typecheck", - "format:check": "prettier --single-quote --check README.md CONTRIBUTING.md SECURITY.md docs/legal/privacy.md docs/legal/terms.md package.json turbo.json tsconfig.base.json pnpm-workspace.yaml compose.yaml .appguardrail.json .github/workflows/ci.yml .github/workflows/appguardrail.yml security/appguardrail-contract.json packages/appguardrail-contract/package.json packages/appguardrail-contract/src/verify-contract.mjs packages/appguardrail-contract/src/verify-contract.test.mjs tests/appguardrail-fixtures/dangerous-cors.ts tests/appguardrail-fixtures/oauth-open-redirect.ts docs/security/appguardrail-regressions.md docs/superpowers/specs/2026-08-03-appguardrail-security-gate-design.md docs/superpowers/plans/2026-08-03-appguardrail-security-gate.md .github/workflows/commercial-readiness.yml product/commercial-readiness-policy.json product/capabilities.json packages/commercial-readiness/package.json packages/commercial-readiness/src/schema.mjs packages/commercial-readiness/src/schema.test.mjs packages/commercial-readiness/src/audit.mjs packages/commercial-readiness/src/audit.test.mjs packages/commercial-readiness/src/pr-gate.mjs packages/commercial-readiness/src/pr-gate.test.mjs packages/commercial-readiness/src/render.mjs packages/commercial-readiness/src/render.test.mjs packages/commercial-readiness/src/github-client.mjs packages/commercial-readiness/src/github-client.test.mjs packages/commercial-readiness/src/cli.mjs packages/commercial-readiness/src/cli.test.mjs packages/commercial-readiness/src/workflow-contract.test.mjs packages/commercial-readiness/src/legal-contract.test.mjs docs/superpowers/specs/2026-08-03-commercial-readiness-loop-design.md docs/superpowers/plans/2026-08-03-commercial-readiness-loop.md apps/identity-service/src/oauth-http-boundary.ts apps/identity-service/src/oauth-http-application.ts apps/identity-service/src/oauth-http-boundary.test.ts docs/superpowers/plans/2026-08-03-oauth-http-boundary-slice.md apps/identity-service/package.json apps/identity-service/src/main.ts apps/identity-service/src/oauth-http-controller.ts apps/identity-service/src/oauth-http-controller.test.ts apps/identity-service/src/oauth-http.integration.test.ts apps/identity-service/src/identity-runtime.ts apps/identity-service/src/identity-runtime.test.ts docs/superpowers/plans/2026-08-03-oauth-controller-wiring-slice.md apps/identity-service/src/oauth-provider-http-client.ts apps/identity-service/src/tests/oauth-provider-http-client.test.ts docs/superpowers/plans/2026-08-03-oauth-provider-http-client-slice.md apps/identity-service/src/google-oidc-client.ts apps/identity-service/src/google-oidc-client.test.ts docs/superpowers/plans/2026-08-03-google-oidc-verifier-slice.md apps/identity-service/src/github-oauth-client.ts apps/identity-service/src/github-oauth-client.test.ts docs/superpowers/plans/2026-08-03-github-oauth-client-slice.md apps/identity-service/src/oauth-callback-application.ts apps/identity-service/src/oauth-callback-application.test.ts docs/superpowers/plans/2026-08-03-oauth-callback-orchestration-slice.md docs/superpowers/plans/2026-08-03-oauth-callback-runtime-wiring-slice.md docs/superpowers/plans/2026-08-03-oauth-open-redirect-regression-slice.md docs/superpowers/plans/2026-08-03-oauth-http-integration-slice.md apps/planning-service/package.json apps/planning-service/migrations/README.md apps/planning-service/src/main.ts apps/planning-service/src/http-boundary.ts apps/planning-service/src/http-boundary.test.ts apps/planning-service/src/planning-domain.ts apps/planning-service/src/planning-domain.test.ts apps/planning-service/src/planning-runtime.ts apps/planning-service/src/planning-runtime.test.ts apps/planning-service/src/postgres-planning-repository.ts apps/planning-service/src/postgres-planning-repository.test.ts apps/planning-service/src/postgres-planning-repository.integration.test.ts apps/planning-service/src/search.ts apps/planning-service/src/search.test.ts apps/planning-service/src/postgres-planning-search.test.ts docs/superpowers/plans/2026-08-03-planning-postgres-repository-slice.md docs/superpowers/plans/2026-08-04-planning-postgres-runtime-slice.md apps/habit-service/package.json apps/habit-service/migrations/README.md apps/habit-service/src/main.ts apps/habit-service/src/habit-domain.ts apps/habit-service/src/habit-domain.test.ts apps/habit-service/src/postgres-habit-repository.ts apps/habit-service/src/postgres-habit-repository.test.ts apps/habit-service/src/postgres-habit-repository.integration.test.ts apps/habit-service/src/habit-runtime.ts apps/habit-service/src/habit-runtime.test.ts apps/habit-service/src/http-boundary.ts apps/habit-service/src/http-boundary.test.ts apps/habit-service/src/habit-service.integration.test.ts docs/superpowers/plans/2026-08-04-habit-recurring-domain-slice.md docs/superpowers/plans/2026-08-04-habit-postgres-repository-slice.md docs/superpowers/plans/2026-08-04-habit-http-api-slice.md apps/ai-service/package.json apps/ai-service/tsconfig.json apps/ai-service/src/main.ts apps/ai-service/src/proposal-service.ts apps/ai-service/src/proposal-service.test.ts apps/ai-service/src/no-silent-mutation.integration.test.ts apps/ai-service/migrations/README.md apps/ai-service/src/proposal-audit-domain.ts apps/ai-service/src/proposal-audit-domain.test.ts apps/ai-service/src/postgres-proposal-audit-repository.ts apps/ai-service/src/postgres-proposal-audit-repository.test.ts apps/ai-service/src/postgres-proposal-audit-repository.integration.test.ts apps/ai-service/src/proposal-audit-application.ts apps/ai-service/src/proposal-audit-application.test.ts apps/ai-service/src/ai-runtime.ts apps/ai-service/src/ai-runtime.test.ts apps/ai-service/src/proposal-audit-http.integration.test.ts docs/superpowers/plans/2026-08-04-ai-proposal-audit-repository-slice.md docs/superpowers/plans/2026-08-04-ai-proposal-audit-api-slice.md apps/gateway/package.json apps/gateway/src/app.module.ts apps/gateway/src/main.ts apps/gateway/src/observability.ts apps/gateway/src/observability.test.ts packages/observability/package.json packages/observability/src/index.cjs packages/observability/src/index.d.ts packages/observability/src/index.test.cjs infra/observability/prometheus.yml infra/observability/alerts.yml docs/operations/service-level-objectives.md docs/superpowers/plans/2026-08-04-observability-slo-foundation-slice.md apps/planning-service/src/observability.ts apps/planning-service/src/observability.test.ts infra/observability/planning-alerts.yml docs/operations/planning-service-level-objectives.md docs/superpowers/plans/2026-08-04-gateway-structured-logging-slice.md", + "format:check": "prettier --single-quote --check README.md CONTRIBUTING.md SECURITY.md docs/legal/privacy.md docs/legal/terms.md package.json turbo.json tsconfig.base.json pnpm-workspace.yaml compose.yaml .appguardrail.json .github/workflows/ci.yml .github/workflows/appguardrail.yml security/appguardrail-contract.json packages/appguardrail-contract/package.json packages/appguardrail-contract/src/verify-contract.mjs packages/appguardrail-contract/src/verify-contract.test.mjs tests/appguardrail-fixtures/dangerous-cors.ts tests/appguardrail-fixtures/oauth-open-redirect.ts docs/security/appguardrail-regressions.md docs/superpowers/specs/2026-08-03-appguardrail-security-gate-design.md docs/superpowers/plans/2026-08-03-appguardrail-security-gate.md .github/workflows/commercial-readiness.yml product/commercial-readiness-policy.json product/capabilities.json packages/commercial-readiness/package.json packages/commercial-readiness/src/schema.mjs packages/commercial-readiness/src/schema.test.mjs packages/commercial-readiness/src/audit.mjs packages/commercial-readiness/src/audit.test.mjs packages/commercial-readiness/src/pr-gate.mjs packages/commercial-readiness/src/pr-gate.test.mjs packages/commercial-readiness/src/render.mjs packages/commercial-readiness/src/render.test.mjs packages/commercial-readiness/src/github-client.mjs packages/commercial-readiness/src/github-client.test.mjs packages/commercial-readiness/src/cli.mjs packages/commercial-readiness/src/cli.test.mjs packages/commercial-readiness/src/workflow-contract.test.mjs packages/commercial-readiness/src/legal-contract.test.mjs docs/superpowers/specs/2026-08-03-commercial-readiness-loop-design.md docs/superpowers/plans/2026-08-03-commercial-readiness-loop.md apps/identity-service/src/oauth-http-boundary.ts apps/identity-service/src/oauth-http-application.ts apps/identity-service/src/oauth-http-boundary.test.ts docs/superpowers/plans/2026-08-03-oauth-http-boundary-slice.md apps/identity-service/package.json apps/identity-service/src/main.ts apps/identity-service/src/oauth-http-controller.ts apps/identity-service/src/oauth-http-controller.test.ts apps/identity-service/src/oauth-http.integration.test.ts apps/identity-service/src/identity-runtime.ts apps/identity-service/src/identity-runtime.test.ts docs/superpowers/plans/2026-08-03-oauth-controller-wiring-slice.md apps/identity-service/src/oauth-provider-http-client.ts apps/identity-service/src/tests/oauth-provider-http-client.test.ts docs/superpowers/plans/2026-08-03-oauth-provider-http-client-slice.md apps/identity-service/src/google-oidc-client.ts apps/identity-service/src/google-oidc-client.test.ts docs/superpowers/plans/2026-08-03-google-oidc-verifier-slice.md apps/identity-service/src/github-oauth-client.ts apps/identity-service/src/github-oauth-client.test.ts docs/superpowers/plans/2026-08-03-github-oauth-client-slice.md apps/identity-service/src/oauth-callback-application.ts apps/identity-service/src/oauth-callback-application.test.ts docs/superpowers/plans/2026-08-03-oauth-callback-orchestration-slice.md docs/superpowers/plans/2026-08-03-oauth-callback-runtime-wiring-slice.md docs/superpowers/plans/2026-08-03-oauth-open-redirect-regression-slice.md docs/superpowers/plans/2026-08-03-oauth-http-integration-slice.md apps/planning-service/package.json apps/planning-service/migrations/README.md apps/planning-service/src/main.ts apps/planning-service/src/http-boundary.ts apps/planning-service/src/http-boundary.test.ts apps/planning-service/src/planning-domain.ts apps/planning-service/src/planning-domain.test.ts apps/planning-service/src/planning-runtime.ts apps/planning-service/src/planning-runtime.test.ts apps/planning-service/src/postgres-planning-repository.ts apps/planning-service/src/postgres-planning-repository.test.ts apps/planning-service/src/postgres-planning-repository.integration.test.ts apps/planning-service/src/search.ts apps/planning-service/src/search.test.ts apps/planning-service/src/postgres-planning-search.test.ts docs/superpowers/plans/2026-08-03-planning-postgres-repository-slice.md docs/superpowers/plans/2026-08-04-planning-postgres-runtime-slice.md apps/habit-service/package.json apps/habit-service/migrations/README.md apps/habit-service/src/main.ts apps/habit-service/src/habit-domain.ts apps/habit-service/src/habit-domain.test.ts apps/habit-service/src/postgres-habit-repository.ts apps/habit-service/src/postgres-habit-repository.test.ts apps/habit-service/src/postgres-habit-repository.integration.test.ts apps/habit-service/src/habit-runtime.ts apps/habit-service/src/habit-runtime.test.ts apps/habit-service/src/http-boundary.ts apps/habit-service/src/http-boundary.test.ts apps/habit-service/src/habit-service.integration.test.ts docs/superpowers/plans/2026-08-04-habit-recurring-domain-slice.md docs/superpowers/plans/2026-08-04-habit-postgres-repository-slice.md docs/superpowers/plans/2026-08-04-habit-http-api-slice.md apps/ai-service/package.json apps/ai-service/tsconfig.json apps/ai-service/src/main.ts apps/ai-service/src/proposal-service.ts apps/ai-service/src/proposal-service.test.ts apps/ai-service/src/no-silent-mutation.integration.test.ts apps/ai-service/migrations/README.md apps/ai-service/src/proposal-audit-domain.ts apps/ai-service/src/proposal-audit-domain.test.ts apps/ai-service/src/postgres-proposal-audit-repository.ts apps/ai-service/src/postgres-proposal-audit-repository.test.ts apps/ai-service/src/postgres-proposal-audit-repository.integration.test.ts apps/ai-service/src/proposal-audit-application.ts apps/ai-service/src/proposal-audit-application.test.ts apps/ai-service/src/ai-runtime.ts apps/ai-service/src/ai-runtime.test.ts apps/ai-service/src/proposal-audit-http.integration.test.ts docs/superpowers/plans/2026-08-04-ai-proposal-audit-repository-slice.md docs/superpowers/plans/2026-08-04-ai-proposal-audit-api-slice.md apps/gateway/package.json apps/gateway/src/app.module.ts apps/gateway/src/main.ts apps/gateway/src/observability.ts apps/gateway/src/observability.test.ts packages/observability/package.json packages/observability/src/index.cjs packages/observability/src/index.d.ts packages/observability/src/index.test.cjs infra/observability/prometheus.yml infra/observability/alerts.yml docs/operations/service-level-objectives.md docs/superpowers/plans/2026-08-04-observability-slo-foundation-slice.md apps/planning-service/src/observability.ts apps/planning-service/src/observability.test.ts infra/observability/planning-alerts.yml docs/operations/planning-service-level-objectives.md docs/superpowers/plans/2026-08-04-gateway-structured-logging-slice.md apps/ai-service/vitest.config.ts apps/ai-service/src/docstring-coverage.test.ts docs/operations/ai-proposal-audit-assurance.md docs/superpowers/specs/2026-08-04-ai-service-quality-gates-design.md docs/superpowers/plans/2026-08-04-ai-service-quality-gates.md apps/ai-service/src/server.ts apps/ai-service/src/quality-coverage.test.ts apps/ai-service/src/server.test.ts", "format": "prettier --single-quote --write ." }, "devDependencies": { "prettier": "^3.6.2", "turbo": "^2.5.6", "typescript": "^5.9.2" + }, + "pnpm": { + "overrides": { + "postcss": "8.5.23", + "sharp": "0.35.0" + } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 00000000..7bd54fba --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,5109 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +overrides: + postcss: 8.5.23 + sharp: 0.35.0 + +importers: + + .: + devDependencies: + prettier: + specifier: ^3.6.2 + version: 3.9.6 + turbo: + specifier: ^2.5.6 + version: 2.10.8 + typescript: + specifier: ^5.9.2 + version: 5.9.3 + + apps/ai-service: + dependencies: + '@nestjs/common': + specifier: ^11.1.6 + version: 11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': + specifier: ^11.1.6 + version: 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.28)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-express': + specifier: ^11.1.6 + version: 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28) + pg: + specifier: ^8.22.0 + version: 8.22.0 + reflect-metadata: + specifier: ^0.2.2 + version: 0.2.2 + rxjs: + specifier: ^7.8.2 + version: 7.8.2 + devDependencies: + '@nestjs/cli': + specifier: ^11.0.10 + version: 11.0.24(@types/node@24.13.3)(prettier@3.9.6) + '@types/node': + specifier: ^24.3.0 + version: 24.13.3 + '@types/pg': + specifier: ^8.20.0 + version: 8.20.3 + '@vitest/coverage-v8': + specifier: ^3.2.4 + version: 3.2.7(vitest@3.2.7(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5)) + typescript: + specifier: ^5.9.2 + version: 5.9.3 + vitest: + specifier: ^3.2.4 + version: 3.2.7(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5) + + apps/gateway: + dependencies: + '@life-os/contracts': + specifier: workspace:* + version: link:../../packages/contracts + '@life-os/observability': + specifier: workspace:* + version: link:../../packages/observability + '@nestjs/common': + specifier: ^11.1.6 + version: 11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': + specifier: ^11.1.6 + version: 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.28)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-express': + specifier: ^11.1.6 + version: 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28) + reflect-metadata: + specifier: ^0.2.2 + version: 0.2.2 + rxjs: + specifier: ^7.8.2 + version: 7.8.2 + devDependencies: + '@nestjs/cli': + specifier: ^11.0.10 + version: 11.0.24(@types/node@24.13.3)(prettier@3.9.6) + '@types/node': + specifier: ^24.3.0 + version: 24.13.3 + typescript: + specifier: ^5.9.2 + version: 5.9.3 + vitest: + specifier: ^3.2.4 + version: 3.2.7(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5) + + apps/habit-service: + dependencies: + '@nestjs/common': + specifier: ^11.1.6 + version: 11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': + specifier: ^11.1.6 + version: 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.28)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-express': + specifier: ^11.1.6 + version: 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28) + pg: + specifier: ^8.22.0 + version: 8.22.0 + reflect-metadata: + specifier: ^0.2.2 + version: 0.2.2 + rxjs: + specifier: ^7.8.2 + version: 7.8.2 + devDependencies: + '@nestjs/cli': + specifier: ^11.0.10 + version: 11.0.24(@types/node@24.13.3)(prettier@3.9.6) + '@types/node': + specifier: ^24.3.0 + version: 24.13.3 + '@types/pg': + specifier: ^8.20.0 + version: 8.20.3 + typescript: + specifier: ^5.9.2 + version: 5.9.3 + vitest: + specifier: ^3.2.4 + version: 3.2.7(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5) + + apps/identity-service: + dependencies: + '@nestjs/common': + specifier: ^11.1.6 + version: 11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': + specifier: ^11.1.6 + version: 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.28)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-express': + specifier: ^11.1.6 + version: 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28) + pg: + specifier: ^8.22.0 + version: 8.22.0 + reflect-metadata: + specifier: ^0.2.2 + version: 0.2.2 + rxjs: + specifier: ^7.8.2 + version: 7.8.2 + devDependencies: + '@nestjs/cli': + specifier: ^11.0.10 + version: 11.0.24(@types/node@24.13.3)(prettier@3.9.6) + '@types/node': + specifier: ^24.3.0 + version: 24.13.3 + '@types/pg': + specifier: ^8.20.0 + version: 8.20.3 + typescript: + specifier: ^5.9.2 + version: 5.9.3 + vitest: + specifier: ^3.2.4 + version: 3.2.7(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5) + + apps/integration-calendar-service: + dependencies: + '@nestjs/common': + specifier: ^11.1.6 + version: 11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': + specifier: ^11.1.6 + version: 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.28)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-express': + specifier: ^11.1.6 + version: 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28) + reflect-metadata: + specifier: ^0.2.2 + version: 0.2.2 + rxjs: + specifier: ^7.8.2 + version: 7.8.2 + devDependencies: + '@nestjs/cli': + specifier: ^11.0.10 + version: 11.0.24(@types/node@24.13.3)(prettier@3.9.6) + '@types/node': + specifier: ^24.3.0 + version: 24.13.3 + typescript: + specifier: ^5.9.2 + version: 5.9.3 + vitest: + specifier: ^3.2.4 + version: 3.2.7(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5) + + apps/integration-service: + dependencies: + '@life-os/plugin-sdk': + specifier: workspace:* + version: link:../../packages/plugin-sdk + '@nestjs/common': + specifier: ^11.1.6 + version: 11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': + specifier: ^11.1.6 + version: 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.28)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-express': + specifier: ^11.1.6 + version: 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28) + reflect-metadata: + specifier: ^0.2.2 + version: 0.2.2 + rxjs: + specifier: ^7.8.2 + version: 7.8.2 + devDependencies: + '@nestjs/cli': + specifier: ^11.0.10 + version: 11.0.24(@types/node@24.13.3)(prettier@3.9.6) + '@types/node': + specifier: ^24.3.0 + version: 24.13.3 + typescript: + specifier: ^5.9.2 + version: 5.9.3 + vitest: + specifier: ^3.2.4 + version: 3.2.7(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5) + + apps/notification-service: + dependencies: + '@nestjs/common': + specifier: ^11.1.6 + version: 11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2) + pg: + specifier: ^8.22.0 + version: 8.22.0 + devDependencies: + '@types/node': + specifier: ^24.3.0 + version: 24.13.3 + '@types/pg': + specifier: ^8.20.0 + version: 8.20.3 + '@vitest/coverage-v8': + specifier: ^3.2.4 + version: 3.2.7(vitest@3.2.7(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5)) + typescript: + specifier: ^5.9.2 + version: 5.9.3 + vitest: + specifier: ^3.2.4 + version: 3.2.7(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5) + + apps/planning-service: + dependencies: + '@life-os/observability': + specifier: workspace:* + version: link:../../packages/observability + '@nestjs/common': + specifier: ^11.1.6 + version: 11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': + specifier: ^11.1.6 + version: 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.28)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-express': + specifier: ^11.1.6 + version: 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28) + pg: + specifier: ^8.22.0 + version: 8.22.0 + reflect-metadata: + specifier: ^0.2.2 + version: 0.2.2 + rxjs: + specifier: ^7.8.2 + version: 7.8.2 + devDependencies: + '@nestjs/cli': + specifier: ^11.0.10 + version: 11.0.24(@types/node@24.13.3)(prettier@3.9.6) + '@types/node': + specifier: ^24.3.0 + version: 24.13.3 + '@types/pg': + specifier: ^8.20.0 + version: 8.20.3 + typescript: + specifier: ^5.9.2 + version: 5.9.3 + vitest: + specifier: ^3.2.4 + version: 3.2.7(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5) + + apps/review-service: + dependencies: + '@nestjs/common': + specifier: ^11.1.6 + version: 11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': + specifier: ^11.1.6 + version: 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.28)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-express': + specifier: ^11.1.6 + version: 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28) + pg: + specifier: ^8.22.0 + version: 8.22.0 + reflect-metadata: + specifier: ^0.2.2 + version: 0.2.2 + rxjs: + specifier: ^7.8.2 + version: 7.8.2 + devDependencies: + '@nestjs/cli': + specifier: ^11.0.10 + version: 11.0.24(@types/node@24.13.3)(prettier@3.9.6) + '@types/node': + specifier: ^24.3.0 + version: 24.13.3 + '@types/pg': + specifier: ^8.20.0 + version: 8.20.3 + prettier: + specifier: ^3.6.2 + version: 3.9.6 + typescript: + specifier: ^5.9.2 + version: 5.9.3 + vitest: + specifier: ^3.2.4 + version: 3.2.7(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5) + + apps/web: + dependencies: + next: + specifier: ^15.5.2 + version: 15.5.22(@playwright/test@1.62.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: + specifier: ^19.1.1 + version: 19.2.8 + react-dom: + specifier: ^19.1.1 + version: 19.2.8(react@19.2.8) + devDependencies: + '@playwright/test': + specifier: ^1.55.0 + version: 1.62.1 + '@types/node': + specifier: ^24.3.0 + version: 24.13.3 + '@types/react': + specifier: ^19.1.12 + version: 19.2.18 + '@types/react-dom': + specifier: ^19.1.9 + version: 19.2.4(@types/react@19.2.18) + tsx: + specifier: ^4.20.5 + version: 4.23.5 + typescript: + specifier: ^5.9.2 + version: 5.9.3 + + infra/tests: + devDependencies: + '@types/node': + specifier: ^24.3.0 + version: 24.13.3 + typescript: + specifier: ^5.9.2 + version: 5.9.3 + vitest: + specifier: ^3.2.4 + version: 3.2.7(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5) + + packages/appguardrail-contract: {} + + packages/commercial-readiness: {} + + packages/contracts: {} + + packages/observability: + devDependencies: + '@types/node': + specifier: ^24.3.0 + version: 24.13.3 + typescript: + specifier: ^5.9.2 + version: 5.9.3 + + packages/plugin-sdk: + devDependencies: + '@types/node': + specifier: ^24.3.0 + version: 24.13.3 + typescript: + specifier: ^5.9.2 + version: 5.9.3 + vitest: + specifier: ^3.2.4 + version: 3.2.7(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5) + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@angular-devkit/core@19.2.24': + resolution: {integrity: sha512-Kd49warf6U/EyWe5BszF/eebN3zQ3bk7tgfEljAw8q/rX95UUtriJubWvp6pgzHfzBA4jwq8f+QiNZB8eBEXPA==} + engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + peerDependencies: + chokidar: ^4.0.0 + peerDependenciesMeta: + chokidar: + optional: true + + '@angular-devkit/core@19.2.27': + resolution: {integrity: sha512-3amNzoCVSKd7ah6l6lBQL4onwwJvqvam7FMoQBILrxtW5LB5ezh8gMSPuA4zJjKjoRzf9uoWdlzqv/84I52xZA==} + engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + peerDependencies: + chokidar: ^4.0.0 + peerDependenciesMeta: + chokidar: + optional: true + + '@angular-devkit/schematics-cli@19.2.27': + resolution: {integrity: sha512-wHYH6SVXVykhLzovUHtYor3Nl4SpIiITi7r9DQDaKYUD4hpRBx25W6N9eGuakT9Vd5tV/x6wmvQFWQZQwFB7eA==} + engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + hasBin: true + + '@angular-devkit/schematics@19.2.24': + resolution: {integrity: sha512-lnw+ZM1Io+cJAkReC0NPDjqObL8NtKzKIkdgEEKC8CUmkhurYhedbicN8Y8NYHgG1uLd2GozW3+/QqPRZaN+Lw==} + engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + + '@angular-devkit/schematics@19.2.27': + resolution: {integrity: sha512-/PZmyAlb2NGWPikRRuiWLdfHQd8Wrx6lX4HqvTcaDhlU43M3T0ud4PH2T3QDp7BzHYY92xtD8iPxX2asg67G1A==} + engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.8': + resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@1.0.2': + resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} + engines: {node: '>=18'} + + '@borewit/text-codec@0.2.2': + resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} + + '@colors/colors@1.5.0': + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + + '@esbuild/aix-ppc64@0.28.1': + resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.28.1': + resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.28.1': + resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.28.1': + resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.28.1': + resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.1': + resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.28.1': + resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.1': + resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.28.1': + resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.28.1': + resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.28.1': + resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.28.1': + resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.28.1': + resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.28.1': + resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.1': + resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.28.1': + resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.28.1': + resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.28.1': + resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.1': + resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.28.1': + resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.1': + resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.28.1': + resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.28.1': + resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.28.1': + resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.28.1': + resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.28.1': + resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.35.0': + resolution: {integrity: sha512-ZgaYEwaj+lx/5n4W8GmZ2IYz0PQHjN5eqRcfijWGB+2Aq7ZInZGa0qJyAn6DEtyLuWHRSrmWOqT9q3qqTBvmUQ==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.35.0': + resolution: {integrity: sha512-c1z9LFpKB0slQW3RchwBE8iSVzGp70TNjUUO9k4BZwwW4HH7JBGHeIy4b+kk4n/kcBASb9evKCE3/7Slmslgiw==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [darwin] + + '@img/sharp-freebsd-wasm32@0.35.0': + resolution: {integrity: sha512-Li2KTev0H90kEtnJHkI9xQojXt1AqWmFBMXiPw5kqd1jQgP7gi5HVK/qC5Rmh/59NuAwUuPzzPITmX22NomYYQ==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-libvips-darwin-arm64@1.3.0': + resolution: {integrity: sha512-EKbmBKtyTH+GPFDRw2TgK2oV6hyxxlJVIar4hoTYSNmIwipgMFdxPQqR392GmfdsPGWga0mCFN1cCKjRb9cljw==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.3.0': + resolution: {integrity: sha512-Pl2OmOvrJ42adUllESxBsG54PfXLo1OYg9i3c5/5Ln/qJ0gZuTM9YMhQJPIbXqwidLRc/c2zuHt4RsrymmNv7A==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.3.0': + resolution: {integrity: sha512-C0SqjoFKnszqa44EQ7xoaT48nnO0lOyXEULfXMWi8krrjOPGYkeK30Okzla6ATbBYsyZ0ySinK0FVkpv3DwzfQ==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.3.0': + resolution: {integrity: sha512-A8UpHoUDW4DwnXoV6+q3C1s7QLRAHtPDEjWuNZjwHMyoCNZnm0GeNN8ls9f/bsEYTRQRW96C/n34XJQHJ2fT7A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.3.0': + resolution: {integrity: sha512-WOpkVxAjFd369iaIzEgNRreFD+gWdUMIGD5zplhNKNeqS6mm5dac3q2AFyCBmzYoAdouzZvRBgxy4z8QHZb4/A==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.3.0': + resolution: {integrity: sha512-DRWw0mOHusrCCuw2rqP87oLg6PGlkomVDFqw2hIwsSfwWpu4k3XLcBPaKKl6ct/GtL/cwNkgwjV/tc0Mqht3VA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.3.0': + resolution: {integrity: sha512-9APy+nFWhHS+kzLgWZfLcyrUd7YqnAQVa4BPOo4xkoHpdoktOAPG4cEr9+Jpl0TtqfVmcMJimNL5qNTyyOHZNA==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.3.0': + resolution: {integrity: sha512-y9RNUYDe2A1UAdhLyfeOodGRszQdaEoe4nfOpp/sNVPl2CWIcUyFaDoCh4vPLPxu19803j2naLqZup2WxDXCLA==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.3.0': + resolution: {integrity: sha512-cC1wkC0Mlucd0KSiGrLkJnB/ZqPvZCntc/Lk7ZnYO5ZSbF2euNek4Xvxafojq+wN1q/W0eprdpUIjUr/EV2PBg==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.3.0': + resolution: {integrity: sha512-LiYMhUZicB1QG//+RvmYZpXJO8fYRENfp+MZUCnG9aw+AKvGAy9gPaCnuwsPcBFs8EV66M0NNxj9VHcNklE8zw==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.35.0': + resolution: {integrity: sha512-4+4XHLNT5wDT0roYlHTEmH9lDKt0acf9Tv+3hM3iceOirkxrR404/3WjAYZ9F9CkHrxeRcGLJXbi4vluMZ9O+A==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.35.0': + resolution: {integrity: sha512-VVlpEWwizEFIOom0zdoeKuO5nuTswzVE5uHcBNvHzmeHUpNFajY3HFfbQ+zIH4E2kVaZ/yVxmsShW56TtEy4uA==} + engines: {node: '>=20.9.0'} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.35.0': + resolution: {integrity: sha512-N3hzbEpUTJC8pWpPVJvgzGxM+so/MAXc8O2s/53B0LL9ZGpfXpME7Wizkc5d/8fRBlBtkDjzoZGDCqqNDHqLEw==} + engines: {node: '>=20.9.0'} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.35.0': + resolution: {integrity: sha512-l6vmKVPnbS0RhVMbyxP5meAARsbhCnBN4fy31qz0+3a6Rv4jEqfzDrT89y6ZPkCi0AJGnwp2En528yXo401Hpw==} + engines: {node: '>=20.9.0'} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.35.0': + resolution: {integrity: sha512-MYlMiPFiv/EKPAHnp3yNZ9AAWFsxga9c5Bkc6wkar6bqzHLlkGVJHRm0u1ei+VXnZxp3Mz9MG9ZIsI8vSOf3sQ==} + engines: {node: '>=20.9.0'} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.35.0': + resolution: {integrity: sha512-TYaItB5oj1ioXjhyn2xrR208vf+YuIIcHptQWRRaBmFhvIvL9D72DXN8w75xup0KXA8UdEAhQ9Qb2S49FD/9Cw==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.35.0': + resolution: {integrity: sha512-DSTb6ijQzqe6DdAaOBVqJ/SYf1vO8EW5bK6X6LRXufEBebf2722VCdvBUtZ3rtV0x2ApfPNDy/p7LrrjaWjiyQ==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.35.0': + resolution: {integrity: sha512-K7ykQ+26Rt6+4BTU80AuGgTPIYX86UxiAKT4rcXX/WNTo7k1ZxpKz+TguHnwVpCqQK3B5PK0vZ0ZBe6nz/ib1w==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.35.0': + resolution: {integrity: sha512-9woLIFORERCr+6cWu87dQ22J34EExkhc73U1kZW0c+RclQqWetoodByp4dWZ/hN8/KVmTRAx2HOnUwib8AwZdA==} + engines: {node: '>=20.9.0'} + + '@img/sharp-webcontainers-wasm32@0.35.0': + resolution: {integrity: sha512-t+kie1TOyaDM6Dho+f+y0VqIUNhYQaKCUahuZVi0E0frgdiaOaPsDxDW3wfKacUdaNBCnK/ZDBMg33ydvHj8uA==} + engines: {node: '>=20.9.0'} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.35.0': + resolution: {integrity: sha512-M5eKxug0dabbaWgFKvPa3odNs2OpaP+81NASfGKkt4GcYXpNhSu7CaeYxWkLNV6vHmUp4hnCxnxrUyhUJhXbKA==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.35.0': + resolution: {integrity: sha512-z0+pZ03QCDvdVN0Ez9IX/yjWC19ikMlXrmdYMwYNLTh2BLPx3hXWPvyqWfquZ0BTO9O6GVOjIVoTcyyacMnWlQ==} + engines: {node: ^20.9.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.35.0': + resolution: {integrity: sha512-feNnlz5ZHKr0MY1LPHvZQyJeBkbo4ctsn0D8FvA53VTw5TC63rfEL2UrWbkSBR19htSE7Mw78xYVwdJqoMWVHw==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [win32] + + '@inquirer/ansi@1.0.2': + resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} + engines: {node: '>=18'} + + '@inquirer/checkbox@4.3.2': + resolution: {integrity: sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/confirm@5.1.21': + resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/core@10.3.2': + resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/editor@4.2.23': + resolution: {integrity: sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/expand@4.0.23': + resolution: {integrity: sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/external-editor@1.0.3': + resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/figures@1.0.15': + resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} + engines: {node: '>=18'} + + '@inquirer/input@4.3.1': + resolution: {integrity: sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/number@3.0.23': + resolution: {integrity: sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/password@4.0.23': + resolution: {integrity: sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/prompts@7.10.1': + resolution: {integrity: sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/prompts@7.3.2': + resolution: {integrity: sha512-G1ytyOoHh5BphmEBxSwALin3n1KGNYB6yImbICcRQdzXfOGbuJ9Jske/Of5Sebk339NSGGNfUshnzK8YWkTPsQ==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/rawlist@4.1.11': + resolution: {integrity: sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/search@3.2.2': + resolution: {integrity: sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/select@4.4.2': + resolution: {integrity: sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/type@3.0.10': + resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@istanbuljs/schema@0.1.6': + resolution: {integrity: sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==} + engines: {node: '>=8'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@lukeed/csprng@1.1.0': + resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} + engines: {node: '>=8'} + + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} + engines: {node: ^22.20 || ^24.12 || >=25} + cpu: [x64] + os: [linux] + + '@nestjs/cli@11.0.24': + resolution: {integrity: sha512-aIHxQLSYtXShifA3zwWIeznEsZnNa3Iz2QRykFj+sl9IcbERBHr5nH87FRgywM+He3NxoF5WazHfR8FsmVeWxw==} + engines: {node: '>= 20.11'} + hasBin: true + peerDependencies: + '@swc/cli': ^0.1.62 || ^0.3.0 || ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0 || ^0.8.0 + '@swc/core': ^1.3.62 + peerDependenciesMeta: + '@swc/cli': + optional: true + '@swc/core': + optional: true + + '@nestjs/common@11.1.28': + resolution: {integrity: sha512-bRImsxibie+AM7xjdwcrm/gr5YeacI65kSBNzTufa1Ib5iwziaY/lqMtRh9THq6pbV4e1HP9aI2ZxGUumnmaoQ==} + peerDependencies: + class-transformer: '>=0.4.1' + class-validator: '>=0.13.2' + reflect-metadata: ^0.1.12 || ^0.2.0 + rxjs: ^7.1.0 + peerDependenciesMeta: + class-transformer: + optional: true + class-validator: + optional: true + + '@nestjs/core@11.1.28': + resolution: {integrity: sha512-06m63xIRj8+l8uOeh/8LnYupGubkyu4f+bPKIadaSui6vK9KpXgoz7HveT1yOVLcEt0M0oCOEW5EuEXZkEmBBQ==} + 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 + reflect-metadata: ^0.1.12 || ^0.2.0 + rxjs: ^7.1.0 + peerDependenciesMeta: + '@nestjs/microservices': + optional: true + '@nestjs/platform-express': + optional: true + '@nestjs/websockets': + optional: true + + '@nestjs/platform-express@11.1.28': + resolution: {integrity: sha512-hU+9Sz4m+onHrR5AmelI59QKmY/Re546bPnygnpqqeQdHDiJpBgjWbL4t6Jr73CBpS60cpyng7WzjgphNB9iwA==} + peerDependencies: + '@nestjs/common': ^11.0.0 + '@nestjs/core': ^11.0.0 + + '@nestjs/schematics@11.1.0': + resolution: {integrity: sha512-lVxGZ46tcdItFMoXr6vyKWlnOsm1SZm/GUqAEDvy2RL4Q4O+3bkziAhrO7Y8JLssFUUvNFEGqAizI52WAxhjDw==} + peerDependencies: + prettier: ^3.0.0 + typescript: '>=4.8.2' + peerDependenciesMeta: + prettier: + optional: true + + '@next/env@15.5.22': + resolution: {integrity: sha512-O5BlKb3KtsHkvO0gjjV66PuJnAgCtIEIzwkt50HRAHsQkU1t77eksIXSZV84/WMtZJjWrnDUPKHVRi0D62nSAA==} + + '@next/swc-darwin-arm64@15.5.22': + resolution: {integrity: sha512-/VISwtffSg8+fVvBbXdglsvruCsdbBC4dG25iU6xascKVqfQKsj/OtjGnOEkIS7pX5GB9e9/r5QprpicsGL3gw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@15.5.22': + resolution: {integrity: sha512-NiA9ve8hbiuhG/Q17a2mZDRVxMTtg3rTOgjLnDaLlE+AEPAQlkkuKrfePEbeOrgYmX0U2KGX4EVEn09hXU5GlQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@15.5.22': + resolution: {integrity: sha512-vAPa9vltW+UW/KWtjXeSUFgV3wb1x9d/BeyC6WFI6eBpL0D2f70oGwtOp6193mNW3qusrpgBzMQferPf+Zh8Dw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-arm64-musl@15.5.22': + resolution: {integrity: sha512-iknK80pWlNDnkdSr13bd8mMuG3Z2oTxODwsZHvuMY7caMk77+rBLdHVWsy8v2EVa3ZojJ/+wJX5fnq8va6Gv8A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-x64-gnu@15.5.22': + resolution: {integrity: sha512-penuEdkwU2OOAiS+n4LE8T/VIoCfAI01QcLZTJ2xc3+l4Q22L/DzURocmI2LU1b+8BMQoLAP1Sze3uYAZT05Bg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-linux-x64-musl@15.5.22': + resolution: {integrity: sha512-ZM0BKJm3FZ+guG6WT6PcyOLtp6paZ5tngcJC/uUKvLW4Y0TQnnVi1+UGdo8Q6Yxp5gaS82pmC1rD/oFlhkWB3g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-win32-arm64-msvc@15.5.22': + resolution: {integrity: sha512-rY/YaumrZaS0//94BnHLF5VSRp0GFUO4GvXNuoCBb0cGSci96yO+p1JaNL2aq9YZAYv9cuZRziV02x5IQH/wjg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@15.5.22': + resolution: {integrity: sha512-s5IA4cyrbR2XK/5NWcu5dp8CfPBiKME+UhvNperia7uQybEgg5+LIhGMiY37WQE4rcI4owsDcU4IVUjLoTuDkA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@playwright/test@1.62.1': + resolution: {integrity: sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==} + engines: {node: '>=20'} + hasBin: true + + '@rollup/rollup-android-arm-eabi@4.62.4': + resolution: {integrity: sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.62.4': + resolution: {integrity: sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.62.4': + resolution: {integrity: sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.62.4': + resolution: {integrity: sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.62.4': + resolution: {integrity: sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.62.4': + resolution: {integrity: sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.62.4': + resolution: {integrity: sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.62.4': + resolution: {integrity: sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.62.4': + resolution: {integrity: sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.62.4': + resolution: {integrity: sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.62.4': + resolution: {integrity: sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.62.4': + resolution: {integrity: sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.62.4': + resolution: {integrity: sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.62.4': + resolution: {integrity: sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.62.4': + resolution: {integrity: sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.62.4': + resolution: {integrity: sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.62.4': + resolution: {integrity: sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.62.4': + resolution: {integrity: sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.62.4': + resolution: {integrity: sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.62.4': + resolution: {integrity: sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.62.4': + resolution: {integrity: sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.62.4': + resolution: {integrity: sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.62.4': + resolution: {integrity: sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.62.4': + resolution: {integrity: sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.62.4': + resolution: {integrity: sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q==} + cpu: [x64] + os: [win32] + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@tokenizer/inflate@0.4.1': + resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} + engines: {node: '>=18'} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + + '@turbo/darwin-64@2.10.8': + resolution: {integrity: sha512-po+7rfJfUnFXjWlcoN2RwhErgzCdRtBc1T26vYPcywHlggmCQiQe1uWaE4j+BibI2uY9/2pDoFzMN0rmSaPFOw==} + cpu: [x64] + os: [darwin] + + '@turbo/darwin-arm64@2.10.8': + resolution: {integrity: sha512-+zB2btDJ00lnPRuqOvpVvgl4x34k/djZQGZTTCfjn7JgNCl8QFY5Njo5+dqkY1g/+9gbbsnAvWm9CmJg9ebcXA==} + cpu: [arm64] + os: [darwin] + + '@turbo/linux-64@2.10.8': + resolution: {integrity: sha512-K1dxqiVisyN7cViVsfQLs6xscQbYuI8aO2nbUhFURDACgEDfZRdP/b4CCxeosBJpcMfhYyiibWqJorCnvz9kKg==} + cpu: [x64] + os: [android, linux] + + '@turbo/linux-arm64@2.10.8': + resolution: {integrity: sha512-Gi77ibVnrE1fEmvr+/wBD/yvRqhwp/RQuCp2+//lv1U1wNFFyVg0V7Wj8FG9FXPFAw5QHReo8rxc9+wBSDZjzA==} + cpu: [arm64] + os: [android, linux] + + '@turbo/windows-64@2.10.8': + resolution: {integrity: sha512-znnLO1haJPYTHoKMKwlAvlkjRiYbbhBzME6wIGaMd+fwir23U6jVd1ecaTWWi1fbnRVqxMfgDBKseQ/hLKb83g==} + cpu: [x64] + os: [win32] + + '@turbo/windows-arm64@2.10.8': + resolution: {integrity: sha512-VN30vh3b3Czh2WzYHNTfF1FE0YMZ5aHsLO8dBMGHJewA6792wX6iJR8ZxlzFW6WdOu0gEAKIvlYhfyT81Wkm4Q==} + cpu: [arm64] + os: [win32] + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/eslint-scope@3.7.7': + resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} + + '@types/eslint@9.6.1': + resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/node@24.13.3': + resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==} + + '@types/pg@8.20.3': + resolution: {integrity: sha512-4Tvg+HO6+oQaAkpT8GTYoSExzpGGZz532GXgbbCElWJQeQdMozBWxEKNBhJJpHFjWXsMxqPbyypvj/89FWNoSQ==} + + '@types/react-dom@19.2.4': + resolution: {integrity: sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.18': + resolution: {integrity: sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==} + + '@vitest/coverage-v8@3.2.7': + resolution: {integrity: sha512-NEGWJS2XNu2PfRLQwOO3CTKj1tTETxNBdk454vDxVBhxJYhPaA/eS0nAI0c+1El1P7a60z8+i+ZrQoGESweGKg==} + peerDependencies: + '@vitest/browser': 3.2.7 + vitest: 3.2.7 + peerDependenciesMeta: + '@vitest/browser': + optional: true + + '@vitest/expect@3.2.7': + resolution: {integrity: sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==} + + '@vitest/mocker@3.2.7': + resolution: {integrity: sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@3.2.7': + resolution: {integrity: sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==} + + '@vitest/runner@3.2.7': + resolution: {integrity: sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==} + + '@vitest/snapshot@3.2.7': + resolution: {integrity: sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==} + + '@vitest/spy@3.2.7': + resolution: {integrity: sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==} + + '@vitest/utils@3.2.7': + resolution: {integrity: sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==} + + '@webassemblyjs/ast@1.14.1': + resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + + '@webassemblyjs/floating-point-hex-parser@1.13.2': + resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} + + '@webassemblyjs/helper-api-error@1.13.2': + resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + + '@webassemblyjs/helper-buffer@1.14.1': + resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + + '@webassemblyjs/helper-numbers@1.13.2': + resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': + resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + + '@webassemblyjs/helper-wasm-section@1.14.1': + resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + + '@webassemblyjs/ieee754@1.13.2': + resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + + '@webassemblyjs/leb128@1.13.2': + resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + + '@webassemblyjs/utf8@1.13.2': + resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} + + '@webassemblyjs/wasm-edit@1.14.1': + resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} + + '@webassemblyjs/wasm-gen@1.14.1': + resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + + '@webassemblyjs/wasm-opt@1.14.1': + resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + + '@webassemblyjs/wasm-parser@1.14.1': + resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + + '@webassemblyjs/wast-printer@1.14.1': + resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + + '@xtuc/ieee754@1.2.0': + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + + '@xtuc/long@4.2.2': + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + acorn-import-phases@1.0.4: + resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} + engines: {node: '>=10.13.0'} + peerDependencies: + acorn: ^8.14.0 + + acorn@8.18.0: + resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv-formats@2.1.1: + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-keywords@3.5.2: + resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} + peerDependencies: + ajv: ^6.9.1 + + ajv-keywords@5.1.0: + resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} + peerDependencies: + ajv: ^8.8.2 + + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + ansis@4.2.0: + resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + engines: {node: '>=14'} + + append-field@1.0.0: + resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-timsort@1.0.3: + resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + ast-v8-to-istanbul@0.3.12: + resolution: {integrity: sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + baseline-browser-mapping@2.11.12: + resolution: {integrity: sha512-r7WnVImvVCeFpf2DOXfy41aPWzeNg3H/A2X4dKmy1QL0MSyyk/e7z8ihJ3N6Nn2PsdhkVlqnEfnUE4a05P2aTA==} + engines: {node: '>=6.0.0'} + hasBin: true + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + body-parser@2.3.0: + resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} + engines: {node: '>=18'} + + brace-expansion@1.1.18: + resolution: {integrity: sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==} + + brace-expansion@2.1.4: + resolution: {integrity: sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==} + + brace-expansion@5.0.9: + resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==} + engines: {node: 20 || >=22} + + browserslist@4.28.7: + resolution: {integrity: sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + 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'} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001806: + resolution: {integrity: sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==} + + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chardet@2.2.0: + resolution: {integrity: sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==} + + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} + engines: {node: '>= 16'} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + chrome-trace-event@1.0.4: + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} + + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + + cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + comment-json@5.0.0: + resolution: {integrity: sha512-uiqLcOiVDJtBP8WGkZHEP+FZIhTzP1dxvn59EfoYUi9gqupjrBWVQkO2atDrbnKPwLeotFYDsuNb26uBMqB+hw==} + engines: {node: '>= 6'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + concat-stream@2.0.0: + resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} + engines: {'0': node >= 6.0} + + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + content-type@2.0.0: + resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + engines: {node: '>=18'} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + + cosmiconfig@8.3.6: + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + electron-to-chromium@1.5.400: + resolution: {integrity: sha512-96EWDNjM59SYflgeV5Ylsf4EMiq1a25YjCnJH7cxn/AF2H3pILRweaUnoLax0yKHWdpOzY6JKEu45e8irqZIHA==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + enhanced-resolve@5.24.5: + resolution: {integrity: sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==} + engines: {node: '>=10.13.0'} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-module-lexer@2.3.1: + resolution: {integrity: sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + esbuild@0.28.1: + resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} + engines: {node: '>=12.0.0'} + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + + fast-uri@3.1.5: + resolution: {integrity: sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-type@21.3.4: + resolution: {integrity: sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==} + engines: {node: '>=20'} + + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + fork-ts-checker-webpack-plugin@9.1.0: + resolution: {integrity: sha512-mpafl89VFPJmhnJ1ssH+8wmM2b50n+Rew5x42NeI2U78aRWgtkEtGmctp7iT16UjquJTjorEmIfESj3DxdW84Q==} + engines: {node: '>=14.21.3'} + peerDependencies: + typescript: '>3.6.0' + webpack: ^5.11.0 + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + + fs-monkey@1.1.0: + resolution: {integrity: sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==} + + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + 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-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + 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'} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jest-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} + + js-tokens@10.0.0: + resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + + js-yaml@4.3.1: + resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==} + hasBin: true + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + + jsonfile@6.2.1: + resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + load-esm@1.0.3: + resolution: {integrity: sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==} + engines: {node: '>=13.2.0'} + + loader-runner@4.3.2: + resolution: {integrity: sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==} + engines: {node: '>=6.11.5'} + + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} + engines: {node: 20 || >=22} + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + magicast@0.3.5: + resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + + media-typer@1.1.1: + resolution: {integrity: sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==} + engines: {node: '>= 0.8'} + + memfs@3.5.3: + resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} + engines: {node: '>= 4.0.0'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} + + 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==} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + multer@2.2.0: + resolution: {integrity: sha512-6rdyFg2kLrMh9Jee7/BMPuV9lEAd7lLW2YUpF9/YxR7njyoUwwQ0ZPh3TaIY50Sw6vlyD2HW3wGOkTS4P79xrQ==} + engines: {node: '>= 10.16.0'} + + mute-stream@2.0.0: + resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} + engines: {node: ^18.17.0 || >=20.5.0} + + nanoid@3.3.17: + resolution: {integrity: sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + next@15.5.22: + resolution: {integrity: sha512-mrtal1sRxO4YrlDS98sDuIvGZivKbFix8w7oAL9ZynfOgc3cADQOQgvwtMooc18Qr8bKzvQAcHwHZ0mbJ7zcfQ==} + engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + node-abort-controller@3.1.1: + resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} + + node-emoji@1.11.0: + resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} + + node-releases@2.0.52: + resolution: {integrity: sha512-MRlTqhAfoMx/4mhEbPo3Hi02g9LJZaJkka69V6h67Cb1gjrAG0jsTE4CZX1eptNx+VCAwJmfpnDIF4P0Nh1A7A==} + engines: {node: '>=18'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + + pg-cloudflare@1.4.0: + resolution: {integrity: sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==} + + pg-connection-string@2.14.0: + resolution: {integrity: sha512-XwWDGcLRGCXAR8F/AM5bG7Q+A3Wm2s6QeEjlOKZLlH3UYcguiqCWKyWXVag5TLTIjR7oOJUY8kcADaZgWPyLeg==} + + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-pool@3.14.0: + resolution: {integrity: sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==} + peerDependencies: + pg: '>=8.0' + + pg-protocol@1.15.0: + resolution: {integrity: sha512-cq9sECI5s0+uPUXjbz8ioyPJni6RzsRib0US67i5IoTZKw8fNeYlVE7u8F4dG7vEJJtc5wdD1K189lCCUwqWTQ==} + + pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + + pg@8.22.0: + resolution: {integrity: sha512-8wih1vVIBMxoUM2oB4soJsD9tDnDpLv4OXBJ+EJzFsvycD+lfyIreC2gGHq78f8jbLLt+bvlPTFdFZfJkOuzAA==} + engines: {node: '>= 16.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + + pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} + engines: {node: '>=12'} + + playwright-core@1.62.1: + resolution: {integrity: sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==} + engines: {node: '>=20'} + hasBin: true + + playwright@1.62.1: + resolution: {integrity: sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==} + engines: {node: '>=20'} + hasBin: true + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + + postcss@8.5.23: + resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} + engines: {node: ^10 || ^12 || >=14} + + postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + postgres-bytea@1.0.1: + resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} + engines: {node: '>=0.10.0'} + + postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + + prettier@3.9.6: + resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==} + engines: {node: '>=14'} + hasBin: true + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.15.3: + resolution: {integrity: sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==} + engines: {node: '>=0.6'} + + range-parser@1.3.0: + resolution: {integrity: sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + + react-dom@19.2.8: + resolution: {integrity: sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==} + peerDependencies: + react: ^19.2.8 + + react@19.2.8: + resolution: {integrity: sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==} + engines: {node: '>=0.10.0'} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + + rollup@4.62.4: + resolution: {integrity: sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + schema-utils@3.3.0: + resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} + engines: {node: '>= 10.13.0'} + + schema-utils@4.3.3: + resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} + engines: {node: '>= 10.13.0'} + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + sharp@0.35.0: + resolution: {integrity: sha512-BqvG5XbwPZ4NV0DK90d86leEECMsoa8bO0nqnKWlBDYxri4GJ7c4EDInaF6q20lTh/mATmnDIKWJFfXnoVfH5g==} + engines: {node: '>=20.9.0'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} + engines: {node: '>= 0.4'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-literal@3.1.0: + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + + strtok3@10.3.5: + resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} + engines: {node: '>=18'} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + symbol-observable@4.0.0: + resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} + engines: {node: '>=0.10'} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + terser-webpack-plugin@5.6.1: + resolution: {integrity: sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@minify-html/node': '*' + '@swc/core': '*' + '@swc/css': '*' + '@swc/html': '*' + clean-css: '*' + cssnano: '*' + csso: '*' + esbuild: '*' + html-minifier-terser: '*' + lightningcss: '*' + postcss: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@minify-html/node': + optional: true + '@swc/core': + optional: true + '@swc/css': + optional: true + '@swc/html': + optional: true + clean-css: + optional: true + cssnano: + optional: true + csso: + optional: true + esbuild: + optional: true + html-minifier-terser: + optional: true + lightningcss: + optional: true + postcss: + optional: true + uglify-js: + optional: true + + terser@5.49.1: + resolution: {integrity: sha512-7A2xlQ5EnGT8KPA92dUh6RbRYTVw8hEaEN9L1K68l4UOXFuV511NnAqObGoRqGOQofQcMypisu1s3xawCEHrvA==} + engines: {node: '>=10'} + hasBin: true + + test-exclude@7.0.2: + resolution: {integrity: sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==} + engines: {node: '>=18'} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@4.0.4: + resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} + engines: {node: '>=14.0.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + token-types@6.1.2: + resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} + engines: {node: '>=14.16'} + + tsconfig-paths-webpack-plugin@4.2.0: + resolution: {integrity: sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA==} + engines: {node: '>=10.13.0'} + + tsconfig-paths@4.2.0: + resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} + engines: {node: '>=6'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsx@4.23.5: + resolution: {integrity: sha512-rw55FUaqOoI7RvlQwLbhO4nSDApnQ4/CykPuiQ/EPvtrX3WA9Ig55jIt9VvbBJbzJuj12ueRu4PMZ2SxPVbihg==} + engines: {node: '>=18.0.0'} + hasBin: true + + turbo@2.10.8: + resolution: {integrity: sha512-9+8YX5QOkGXzZxcIykTHgaooRHGMWO+jfdyRK0o+rN0U7hBIig2MrJ8r/aNzIPDPhdA73SGb0O+tIztaModTMg==} + hasBin: true + + 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'} + + typedarray@0.0.6: + resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + uid@2.0.2: + resolution: {integrity: sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==} + engines: {node: '>=8'} + + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vite-node@3.2.4: + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + + vite@7.3.6: + resolution: {integrity: sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.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' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@3.2.7: + resolution: {integrity: sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.2.7 + '@vitest/ui': 3.2.7 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + watchpack@2.5.2: + resolution: {integrity: sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg==} + engines: {node: '>=10.13.0'} + + wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + + webpack-node-externals@3.0.0: + resolution: {integrity: sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==} + engines: {node: '>=6'} + + webpack-sources@3.5.1: + resolution: {integrity: sha512-jyuiGJdtvY434z5bUZrjz67v76/ePNvFZTp9Mdz29IlH4+GPsgyGjiv0fKI+M7BdkU6ADjulUcKAd3tUK3WlEw==} + engines: {node: '>=10.13.0'} + + webpack@5.106.2: + resolution: {integrity: sha512-wGN3qcrBQIFmQ/c0AiOAQBvrZ5lmY8vbbMv4Mxfgzqd/B6+9pXtLo73WuS1dSGXM5QYY3hZnIbvx+K1xxe6FyA==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yoctocolors-cjs@2.1.3: + resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} + engines: {node: '>=18'} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@angular-devkit/core@19.2.24(chokidar@4.0.3)': + dependencies: + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + jsonc-parser: 3.3.1 + picomatch: 4.0.4 + rxjs: 7.8.1 + source-map: 0.7.4 + optionalDependencies: + chokidar: 4.0.3 + + '@angular-devkit/core@19.2.27(chokidar@4.0.3)': + dependencies: + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + jsonc-parser: 3.3.1 + picomatch: 4.0.4 + rxjs: 7.8.1 + source-map: 0.7.4 + optionalDependencies: + chokidar: 4.0.3 + + '@angular-devkit/schematics-cli@19.2.27(@types/node@24.13.3)(chokidar@4.0.3)': + dependencies: + '@angular-devkit/core': 19.2.27(chokidar@4.0.3) + '@angular-devkit/schematics': 19.2.27(chokidar@4.0.3) + '@inquirer/prompts': 7.3.2(@types/node@24.13.3) + ansi-colors: 4.1.3 + symbol-observable: 4.0.0 + yargs-parser: 21.1.1 + transitivePeerDependencies: + - '@types/node' + - chokidar + + '@angular-devkit/schematics@19.2.24(chokidar@4.0.3)': + dependencies: + '@angular-devkit/core': 19.2.24(chokidar@4.0.3) + jsonc-parser: 3.3.1 + magic-string: 0.30.17 + ora: 5.4.1 + rxjs: 7.8.1 + transitivePeerDependencies: + - chokidar + + '@angular-devkit/schematics@19.2.27(chokidar@4.0.3)': + dependencies: + '@angular-devkit/core': 19.2.27(chokidar@4.0.3) + jsonc-parser: 3.3.1 + magic-string: 0.30.17 + ora: 5.4.1 + rxjs: 7.8.1 + transitivePeerDependencies: + - chokidar + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/parser@7.29.8': + dependencies: + '@babel/types': 7.29.8 + + '@babel/types@7.29.8': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@bcoe/v8-coverage@1.0.2': {} + + '@borewit/text-codec@0.2.2': {} + + '@colors/colors@1.5.0': + optional: true + + '@emnapi/runtime@1.11.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.28.1': + optional: true + + '@esbuild/android-arm64@0.28.1': + optional: true + + '@esbuild/android-arm@0.28.1': + optional: true + + '@esbuild/android-x64@0.28.1': + optional: true + + '@esbuild/darwin-arm64@0.28.1': + optional: true + + '@esbuild/darwin-x64@0.28.1': + optional: true + + '@esbuild/freebsd-arm64@0.28.1': + optional: true + + '@esbuild/freebsd-x64@0.28.1': + optional: true + + '@esbuild/linux-arm64@0.28.1': + optional: true + + '@esbuild/linux-arm@0.28.1': + optional: true + + '@esbuild/linux-ia32@0.28.1': + optional: true + + '@esbuild/linux-loong64@0.28.1': + optional: true + + '@esbuild/linux-mips64el@0.28.1': + optional: true + + '@esbuild/linux-ppc64@0.28.1': + optional: true + + '@esbuild/linux-riscv64@0.28.1': + optional: true + + '@esbuild/linux-s390x@0.28.1': + optional: true + + '@esbuild/linux-x64@0.28.1': + optional: true + + '@esbuild/netbsd-arm64@0.28.1': + optional: true + + '@esbuild/netbsd-x64@0.28.1': + optional: true + + '@esbuild/openbsd-arm64@0.28.1': + optional: true + + '@esbuild/openbsd-x64@0.28.1': + optional: true + + '@esbuild/openharmony-arm64@0.28.1': + optional: true + + '@esbuild/sunos-x64@0.28.1': + optional: true + + '@esbuild/win32-arm64@0.28.1': + optional: true + + '@esbuild/win32-ia32@0.28.1': + optional: true + + '@esbuild/win32-x64@0.28.1': + optional: true + + '@img/colour@1.1.0': + optional: true + + '@img/sharp-darwin-arm64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.3.0 + optional: true + + '@img/sharp-darwin-x64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.3.0 + optional: true + + '@img/sharp-freebsd-wasm32@0.35.0': + dependencies: + '@img/sharp-wasm32': 0.35.0 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.3.0': + optional: true + + '@img/sharp-libvips-darwin-x64@1.3.0': + optional: true + + '@img/sharp-libvips-linux-arm64@1.3.0': + optional: true + + '@img/sharp-libvips-linux-arm@1.3.0': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.3.0': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.3.0': + optional: true + + '@img/sharp-libvips-linux-s390x@1.3.0': + optional: true + + '@img/sharp-libvips-linux-x64@1.3.0': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.3.0': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.3.0': + optional: true + + '@img/sharp-linux-arm64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.3.0 + optional: true + + '@img/sharp-linux-arm@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.3.0 + optional: true + + '@img/sharp-linux-ppc64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.3.0 + optional: true + + '@img/sharp-linux-riscv64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.3.0 + optional: true + + '@img/sharp-linux-s390x@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.3.0 + optional: true + + '@img/sharp-linux-x64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.3.0 + optional: true + + '@img/sharp-linuxmusl-arm64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.3.0 + optional: true + + '@img/sharp-linuxmusl-x64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.3.0 + optional: true + + '@img/sharp-wasm32@0.35.0': + dependencies: + '@emnapi/runtime': 1.11.3 + optional: true + + '@img/sharp-webcontainers-wasm32@0.35.0': + dependencies: + '@img/sharp-wasm32': 0.35.0 + optional: true + + '@img/sharp-win32-arm64@0.35.0': + optional: true + + '@img/sharp-win32-ia32@0.35.0': + optional: true + + '@img/sharp-win32-x64@0.35.0': + optional: true + + '@inquirer/ansi@1.0.2': {} + + '@inquirer/checkbox@4.3.2(@types/node@24.13.3)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@24.13.3) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@24.13.3) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 24.13.3 + + '@inquirer/confirm@5.1.21(@types/node@24.13.3)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@24.13.3) + '@inquirer/type': 3.0.10(@types/node@24.13.3) + optionalDependencies: + '@types/node': 24.13.3 + + '@inquirer/core@10.3.2(@types/node@24.13.3)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@24.13.3) + cli-width: 4.1.0 + mute-stream: 2.0.0 + signal-exit: 4.1.0 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 24.13.3 + + '@inquirer/editor@4.2.23(@types/node@24.13.3)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@24.13.3) + '@inquirer/external-editor': 1.0.3(@types/node@24.13.3) + '@inquirer/type': 3.0.10(@types/node@24.13.3) + optionalDependencies: + '@types/node': 24.13.3 + + '@inquirer/expand@4.0.23(@types/node@24.13.3)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@24.13.3) + '@inquirer/type': 3.0.10(@types/node@24.13.3) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 24.13.3 + + '@inquirer/external-editor@1.0.3(@types/node@24.13.3)': + dependencies: + chardet: 2.2.0 + iconv-lite: 0.7.3 + optionalDependencies: + '@types/node': 24.13.3 + + '@inquirer/figures@1.0.15': {} + + '@inquirer/input@4.3.1(@types/node@24.13.3)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@24.13.3) + '@inquirer/type': 3.0.10(@types/node@24.13.3) + optionalDependencies: + '@types/node': 24.13.3 + + '@inquirer/number@3.0.23(@types/node@24.13.3)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@24.13.3) + '@inquirer/type': 3.0.10(@types/node@24.13.3) + optionalDependencies: + '@types/node': 24.13.3 + + '@inquirer/password@4.0.23(@types/node@24.13.3)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@24.13.3) + '@inquirer/type': 3.0.10(@types/node@24.13.3) + optionalDependencies: + '@types/node': 24.13.3 + + '@inquirer/prompts@7.10.1(@types/node@24.13.3)': + dependencies: + '@inquirer/checkbox': 4.3.2(@types/node@24.13.3) + '@inquirer/confirm': 5.1.21(@types/node@24.13.3) + '@inquirer/editor': 4.2.23(@types/node@24.13.3) + '@inquirer/expand': 4.0.23(@types/node@24.13.3) + '@inquirer/input': 4.3.1(@types/node@24.13.3) + '@inquirer/number': 3.0.23(@types/node@24.13.3) + '@inquirer/password': 4.0.23(@types/node@24.13.3) + '@inquirer/rawlist': 4.1.11(@types/node@24.13.3) + '@inquirer/search': 3.2.2(@types/node@24.13.3) + '@inquirer/select': 4.4.2(@types/node@24.13.3) + optionalDependencies: + '@types/node': 24.13.3 + + '@inquirer/prompts@7.3.2(@types/node@24.13.3)': + dependencies: + '@inquirer/checkbox': 4.3.2(@types/node@24.13.3) + '@inquirer/confirm': 5.1.21(@types/node@24.13.3) + '@inquirer/editor': 4.2.23(@types/node@24.13.3) + '@inquirer/expand': 4.0.23(@types/node@24.13.3) + '@inquirer/input': 4.3.1(@types/node@24.13.3) + '@inquirer/number': 3.0.23(@types/node@24.13.3) + '@inquirer/password': 4.0.23(@types/node@24.13.3) + '@inquirer/rawlist': 4.1.11(@types/node@24.13.3) + '@inquirer/search': 3.2.2(@types/node@24.13.3) + '@inquirer/select': 4.4.2(@types/node@24.13.3) + optionalDependencies: + '@types/node': 24.13.3 + + '@inquirer/rawlist@4.1.11(@types/node@24.13.3)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@24.13.3) + '@inquirer/type': 3.0.10(@types/node@24.13.3) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 24.13.3 + + '@inquirer/search@3.2.2(@types/node@24.13.3)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@24.13.3) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@24.13.3) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 24.13.3 + + '@inquirer/select@4.4.2(@types/node@24.13.3)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@24.13.3) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@24.13.3) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 24.13.3 + + '@inquirer/type@3.0.10(@types/node@24.13.3)': + optionalDependencies: + '@types/node': 24.13.3 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@istanbuljs/schema@0.1.6': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@lukeed/csprng@1.1.0': {} + + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + optional: true + + '@nestjs/cli@11.0.24(@types/node@24.13.3)(prettier@3.9.6)': + dependencies: + '@angular-devkit/core': 19.2.27(chokidar@4.0.3) + '@angular-devkit/schematics': 19.2.27(chokidar@4.0.3) + '@angular-devkit/schematics-cli': 19.2.27(@types/node@24.13.3)(chokidar@4.0.3) + '@inquirer/prompts': 7.10.1(@types/node@24.13.3) + '@nestjs/schematics': 11.1.0(chokidar@4.0.3)(prettier@3.9.6)(typescript@5.9.3) + ansis: 4.2.0 + chokidar: 4.0.3 + cli-table3: 0.6.5 + commander: 4.1.1 + fork-ts-checker-webpack-plugin: 9.1.0(typescript@5.9.3)(webpack@5.106.2) + glob: 13.0.6 + node-emoji: 1.11.0 + ora: 5.4.1 + tsconfig-paths: 4.2.0 + tsconfig-paths-webpack-plugin: 4.2.0 + typescript: 5.9.3 + webpack: 5.106.2 + webpack-node-externals: 3.0.0 + transitivePeerDependencies: + - '@minify-html/node' + - '@swc/css' + - '@swc/html' + - '@types/node' + - clean-css + - cssnano + - csso + - esbuild + - html-minifier-terser + - lightningcss + - postcss + - prettier + - uglify-js + - webpack-cli + + '@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2)': + dependencies: + file-type: 21.3.4 + iterare: 1.2.1 + load-esm: 1.0.3 + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + tslib: 2.8.1 + uid: 2.0.2 + transitivePeerDependencies: + - supports-color + + '@nestjs/core@11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.28)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + dependencies: + '@nestjs/common': 11.1.28(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.2.2 + rxjs: 7.8.2 + tslib: 2.8.1 + uid: 2.0.2 + optionalDependencies: + '@nestjs/platform-express': 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28) + + '@nestjs/platform-express@11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28)': + dependencies: + '@nestjs/common': 11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.28(@nestjs/common@11.1.28(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.28)(reflect-metadata@0.2.2)(rxjs@7.8.2) + cors: 2.8.6 + express: 5.2.1 + multer: 2.2.0 + path-to-regexp: 8.4.2 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@nestjs/schematics@11.1.0(chokidar@4.0.3)(prettier@3.9.6)(typescript@5.9.3)': + dependencies: + '@angular-devkit/core': 19.2.24(chokidar@4.0.3) + '@angular-devkit/schematics': 19.2.24(chokidar@4.0.3) + comment-json: 5.0.0 + jsonc-parser: 3.3.1 + pluralize: 8.0.0 + typescript: 5.9.3 + optionalDependencies: + prettier: 3.9.6 + transitivePeerDependencies: + - chokidar + + '@next/env@15.5.22': {} + + '@next/swc-darwin-arm64@15.5.22': + optional: true + + '@next/swc-darwin-x64@15.5.22': + optional: true + + '@next/swc-linux-arm64-gnu@15.5.22': + optional: true + + '@next/swc-linux-arm64-musl@15.5.22': + optional: true + + '@next/swc-linux-x64-gnu@15.5.22': + optional: true + + '@next/swc-linux-x64-musl@15.5.22': + optional: true + + '@next/swc-win32-arm64-msvc@15.5.22': + optional: true + + '@next/swc-win32-x64-msvc@15.5.22': + optional: true + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@playwright/test@1.62.1': + dependencies: + playwright: 1.62.1 + + '@rollup/rollup-android-arm-eabi@4.62.4': + optional: true + + '@rollup/rollup-android-arm64@4.62.4': + optional: true + + '@rollup/rollup-darwin-arm64@4.62.4': + optional: true + + '@rollup/rollup-darwin-x64@4.62.4': + optional: true + + '@rollup/rollup-freebsd-arm64@4.62.4': + optional: true + + '@rollup/rollup-freebsd-x64@4.62.4': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.62.4': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.62.4': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.62.4': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.62.4': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.62.4': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.62.4': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-x64-musl@4.62.4': + optional: true + + '@rollup/rollup-openbsd-x64@4.62.4': + optional: true + + '@rollup/rollup-openharmony-arm64@4.62.4': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.62.4': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.62.4': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.62.4': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.62.4': + optional: true + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@tokenizer/inflate@0.4.1': + dependencies: + debug: 4.4.3 + token-types: 6.1.2 + transitivePeerDependencies: + - supports-color + + '@tokenizer/token@0.3.0': {} + + '@turbo/darwin-64@2.10.8': + optional: true + + '@turbo/darwin-arm64@2.10.8': + optional: true + + '@turbo/linux-64@2.10.8': + optional: true + + '@turbo/linux-arm64@2.10.8': + optional: true + + '@turbo/windows-64@2.10.8': + optional: true + + '@turbo/windows-arm64@2.10.8': + optional: true + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/eslint-scope@3.7.7': + dependencies: + '@types/eslint': 9.6.1 + '@types/estree': 1.0.9 + + '@types/eslint@9.6.1': + dependencies: + '@types/estree': 1.0.9 + '@types/json-schema': 7.0.15 + + '@types/estree@1.0.9': {} + + '@types/json-schema@7.0.15': {} + + '@types/node@24.13.3': + dependencies: + undici-types: 7.18.2 + + '@types/pg@8.20.3': + dependencies: + '@types/node': 24.13.3 + pg-protocol: 1.15.0 + pg-types: 2.2.0 + + '@types/react-dom@19.2.4(@types/react@19.2.18)': + dependencies: + '@types/react': 19.2.18 + + '@types/react@19.2.18': + dependencies: + csstype: 3.2.3 + + '@vitest/coverage-v8@3.2.7(vitest@3.2.7(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5))': + dependencies: + '@ampproject/remapping': 2.3.0 + '@bcoe/v8-coverage': 1.0.2 + ast-v8-to-istanbul: 0.3.12 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + magic-string: 0.30.21 + magicast: 0.3.5 + std-env: 3.10.0 + test-exclude: 7.0.2 + tinyrainbow: 2.0.0 + vitest: 3.2.7(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@3.2.7': + dependencies: + '@types/chai': 5.2.3 + '@vitest/spy': 3.2.7 + '@vitest/utils': 3.2.7 + chai: 5.3.3 + tinyrainbow: 2.0.0 + + '@vitest/mocker@3.2.7(vite@7.3.6(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5))': + dependencies: + '@vitest/spy': 3.2.7 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.6(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5) + + '@vitest/pretty-format@3.2.7': + dependencies: + tinyrainbow: 2.0.0 + + '@vitest/runner@3.2.7': + dependencies: + '@vitest/utils': 3.2.7 + pathe: 2.0.3 + strip-literal: 3.1.0 + + '@vitest/snapshot@3.2.7': + dependencies: + '@vitest/pretty-format': 3.2.7 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@3.2.7': + dependencies: + tinyspy: 4.0.4 + + '@vitest/utils@3.2.7': + dependencies: + '@vitest/pretty-format': 3.2.7 + loupe: 3.2.1 + tinyrainbow: 2.0.0 + + '@webassemblyjs/ast@1.14.1': + dependencies: + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + + '@webassemblyjs/floating-point-hex-parser@1.13.2': {} + + '@webassemblyjs/helper-api-error@1.13.2': {} + + '@webassemblyjs/helper-buffer@1.14.1': {} + + '@webassemblyjs/helper-numbers@1.13.2': + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} + + '@webassemblyjs/helper-wasm-section@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 + + '@webassemblyjs/ieee754@1.13.2': + dependencies: + '@xtuc/ieee754': 1.2.0 + + '@webassemblyjs/leb128@1.13.2': + dependencies: + '@xtuc/long': 4.2.2 + + '@webassemblyjs/utf8@1.13.2': {} + + '@webassemblyjs/wasm-edit@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 + + '@webassemblyjs/wasm-gen@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wasm-opt@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + + '@webassemblyjs/wasm-parser@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wast-printer@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 + + '@xtuc/ieee754@1.2.0': {} + + '@xtuc/long@4.2.2': {} + + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + + acorn-import-phases@1.0.4(acorn@8.18.0): + dependencies: + acorn: 8.18.0 + + acorn@8.18.0: {} + + ajv-formats@2.1.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + + ajv-formats@3.0.1(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + + ajv-keywords@3.5.2(ajv@6.15.0): + dependencies: + ajv: 6.15.0 + + ajv-keywords@5.1.0(ajv@8.20.0): + dependencies: + ajv: 8.20.0 + fast-deep-equal: 3.1.3 + + ajv@6.15.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.5 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.5 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-colors@4.1.3: {} + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + ansis@4.2.0: {} + + append-field@1.0.0: {} + + argparse@2.0.1: {} + + array-timsort@1.0.3: {} + + assertion-error@2.0.1: {} + + ast-v8-to-istanbul@0.3.12: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + estree-walker: 3.0.3 + js-tokens: 10.0.0 + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.11.12: {} + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + body-parser@2.3.0: + dependencies: + bytes: 3.1.2 + content-type: 2.0.0 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.3 + on-finished: 2.4.1 + qs: 6.15.3 + raw-body: 3.0.2 + type-is: 2.1.0 + transitivePeerDependencies: + - supports-color + + brace-expansion@1.1.18: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.1.4: + dependencies: + balanced-match: 1.0.2 + + brace-expansion@5.0.9: + dependencies: + balanced-match: 4.0.4 + + browserslist@4.28.7: + dependencies: + baseline-browser-mapping: 2.11.12 + caniuse-lite: 1.0.30001806 + electron-to-chromium: 1.5.400 + node-releases: 2.0.52 + update-browserslist-db: 1.2.3(browserslist@4.28.7) + + buffer-from@1.1.2: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + + bytes@3.1.2: {} + + cac@6.7.14: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001806: {} + + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.3 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chardet@2.2.0: {} + + check-error@2.1.3: {} + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + chrome-trace-event@1.0.4: {} + + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + + cli-spinners@2.9.2: {} + + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + + cli-width@4.1.0: {} + + client-only@0.0.1: {} + + clone@1.0.4: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + commander@2.20.3: {} + + commander@4.1.1: {} + + comment-json@5.0.0: + dependencies: + array-timsort: 1.0.3 + esprima: 4.0.1 + + concat-map@0.0.1: {} + + concat-stream@2.0.0: + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 3.6.2 + typedarray: 0.0.6 + + content-disposition@1.1.0: {} + + content-type@1.0.5: {} + + content-type@2.0.0: {} + + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + cosmiconfig@8.3.6(typescript@5.9.3): + dependencies: + import-fresh: 3.3.1 + js-yaml: 4.3.1 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 5.9.3 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.2.3: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-eql@5.0.2: {} + + deepmerge@4.3.1: {} + + defaults@1.0.4: + dependencies: + clone: 1.0.4 + + depd@2.0.0: {} + + detect-libc@2.1.2: + optional: true + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + ee-first@1.1.1: {} + + electron-to-chromium@1.5.400: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encodeurl@2.0.0: {} + + enhanced-resolve@5.24.5: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-module-lexer@2.3.1: {} + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + esbuild@0.28.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.1 + '@esbuild/android-arm': 0.28.1 + '@esbuild/android-arm64': 0.28.1 + '@esbuild/android-x64': 0.28.1 + '@esbuild/darwin-arm64': 0.28.1 + '@esbuild/darwin-x64': 0.28.1 + '@esbuild/freebsd-arm64': 0.28.1 + '@esbuild/freebsd-x64': 0.28.1 + '@esbuild/linux-arm': 0.28.1 + '@esbuild/linux-arm64': 0.28.1 + '@esbuild/linux-ia32': 0.28.1 + '@esbuild/linux-loong64': 0.28.1 + '@esbuild/linux-mips64el': 0.28.1 + '@esbuild/linux-ppc64': 0.28.1 + '@esbuild/linux-riscv64': 0.28.1 + '@esbuild/linux-s390x': 0.28.1 + '@esbuild/linux-x64': 0.28.1 + '@esbuild/netbsd-arm64': 0.28.1 + '@esbuild/netbsd-x64': 0.28.1 + '@esbuild/openbsd-arm64': 0.28.1 + '@esbuild/openbsd-x64': 0.28.1 + '@esbuild/openharmony-arm64': 0.28.1 + '@esbuild/sunos-x64': 0.28.1 + '@esbuild/win32-arm64': 0.28.1 + '@esbuild/win32-ia32': 0.28.1 + '@esbuild/win32-x64': 0.28.1 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + + esprima@4.0.1: {} + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@4.3.0: {} + + estraverse@5.3.0: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + etag@1.8.1: {} + + events@3.3.0: {} + + expect-type@1.4.0: {} + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.3.0 + content-disposition: 1.1.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.3 + range-parser: 1.3.0 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.1.0 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + fast-deep-equal@3.1.3: {} + + fast-json-stable-stringify@2.1.0: {} + + fast-safe-stringify@2.1.1: {} + + fast-uri@3.1.5: {} + + fdir@6.5.0(picomatch@4.0.5): + optionalDependencies: + picomatch: 4.0.5 + + file-type@21.3.4: + dependencies: + '@tokenizer/inflate': 0.4.1 + strtok3: 10.3.5 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + transitivePeerDependencies: + - supports-color + + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.3)(webpack@5.106.2): + dependencies: + '@babel/code-frame': 7.29.7 + chalk: 4.1.2 + chokidar: 4.0.3 + cosmiconfig: 8.3.6(typescript@5.9.3) + deepmerge: 4.3.1 + fs-extra: 10.1.0 + memfs: 3.5.3 + minimatch: 3.1.5 + node-abort-controller: 3.1.1 + schema-utils: 3.3.0 + semver: 7.8.5 + tapable: 2.3.3 + typescript: 5.9.3 + webpack: 5.106.2 + + forwarded@0.2.0: {} + + fresh@2.0.0: {} + + fs-extra@10.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.1 + universalify: 2.0.1 + + fs-monkey@1.1.0: {} + + fsevents@2.3.2: + optional: true + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + glob-to-regexp@0.4.1: {} + + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@13.0.6: + dependencies: + minimatch: 10.2.6 + minipass: 7.1.3 + path-scurry: 2.0.2 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + has-symbols@1.1.0: {} + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + html-escaper@2.0.2: {} + + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + iconv-lite@0.7.3: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + inherits@2.0.4: {} + + ipaddr.js@1.9.1: {} + + is-arrayish@0.2.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-interactive@1.0.0: {} + + is-promise@4.0.0: {} + + is-unicode-supported@0.1.0: {} + + 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-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + iterare@1.2.1: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jest-worker@27.5.1: + dependencies: + '@types/node': 24.13.3 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + js-tokens@10.0.0: {} + + js-tokens@4.0.0: {} + + js-tokens@9.0.1: {} + + js-yaml@4.3.1: + dependencies: + argparse: 2.0.1 + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json5@2.2.3: {} + + jsonc-parser@3.3.1: {} + + jsonfile@6.2.1: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + lines-and-columns@1.2.4: {} + + load-esm@1.0.3: {} + + loader-runner@4.3.2: {} + + lodash@4.18.1: {} + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + loupe@3.2.1: {} + + lru-cache@10.4.3: {} + + lru-cache@11.5.2: {} + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magicast@0.3.5: + dependencies: + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + source-map-js: 1.2.1 + + make-dir@4.0.0: + dependencies: + semver: 7.8.5 + + math-intrinsics@1.1.0: {} + + media-typer@0.3.0: {} + + media-typer@1.1.1: {} + + memfs@3.5.3: + dependencies: + fs-monkey: 1.1.0 + + merge-descriptors@2.0.0: {} + + merge-stream@2.0.0: {} + + mime-db@1.52.0: {} + + mime-db@1.54.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + + mimic-fn@2.1.0: {} + + minimatch@10.2.6: + dependencies: + brace-expansion: 5.0.9 + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.18 + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.1.4 + + minimist@1.2.8: {} + + minipass@7.1.3: {} + + ms@2.1.3: {} + + multer@2.2.0: + dependencies: + append-field: 1.0.0 + busboy: 1.6.0 + concat-stream: 2.0.0 + type-is: 1.6.18 + + mute-stream@2.0.0: {} + + nanoid@3.3.17: {} + + negotiator@1.0.0: {} + + neo-async@2.6.2: {} + + next@15.5.22(@playwright/test@1.62.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): + dependencies: + '@next/env': 15.5.22 + '@swc/helpers': 0.5.15 + caniuse-lite: 1.0.30001806 + postcss: 8.5.23 + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + styled-jsx: 5.1.6(react@19.2.8) + optionalDependencies: + '@next/swc-darwin-arm64': 15.5.22 + '@next/swc-darwin-x64': 15.5.22 + '@next/swc-linux-arm64-gnu': 15.5.22 + '@next/swc-linux-arm64-musl': 15.5.22 + '@next/swc-linux-x64-gnu': 15.5.22 + '@next/swc-linux-x64-musl': 15.5.22 + '@next/swc-win32-arm64-msvc': 15.5.22 + '@next/swc-win32-x64-msvc': 15.5.22 + '@playwright/test': 1.62.1 + sharp: 0.35.0 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + node-abort-controller@3.1.1: {} + + node-emoji@1.11.0: + dependencies: + lodash: 4.18.1 + + node-releases@2.0.52: {} + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + ora@5.4.1: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + + package-json-from-dist@1.0.1: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.29.7 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parseurl@1.3.3: {} + + path-key@3.1.1: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + + path-scurry@2.0.2: + dependencies: + lru-cache: 11.5.2 + minipass: 7.1.3 + + path-to-regexp@8.4.2: {} + + path-type@4.0.0: {} + + pathe@2.0.3: {} + + pathval@2.0.1: {} + + pg-cloudflare@1.4.0: + optional: true + + pg-connection-string@2.14.0: {} + + pg-int8@1.0.1: {} + + pg-pool@3.14.0(pg@8.22.0): + dependencies: + pg: 8.22.0 + + pg-protocol@1.15.0: {} + + pg-types@2.2.0: + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.1 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + + pg@8.22.0: + dependencies: + pg-connection-string: 2.14.0 + pg-pool: 3.14.0(pg@8.22.0) + pg-protocol: 1.15.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.4.0 + + pgpass@1.0.5: + dependencies: + split2: 4.2.0 + + picocolors@1.1.1: {} + + picomatch@4.0.4: {} + + picomatch@4.0.5: {} + + playwright-core@1.62.1: {} + + playwright@1.62.1: + dependencies: + playwright-core: 1.62.1 + optionalDependencies: + fsevents: 2.3.2 + + pluralize@8.0.0: {} + + postcss@8.5.23: + dependencies: + nanoid: 3.3.17 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postgres-array@2.0.0: {} + + postgres-bytea@1.0.1: {} + + postgres-date@1.0.7: {} + + postgres-interval@1.2.0: + dependencies: + xtend: 4.0.2 + + prettier@3.9.6: {} + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + punycode@2.3.1: {} + + qs@6.15.3: + dependencies: + es-define-property: 1.0.1 + side-channel: 1.1.1 + + range-parser@1.3.0: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.3 + unpipe: 1.0.0 + + react-dom@19.2.8(react@19.2.8): + dependencies: + react: 19.2.8 + scheduler: 0.27.0 + + react@19.2.8: {} + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdirp@4.1.2: {} + + reflect-metadata@0.2.2: {} + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + + rollup@4.62.4: + dependencies: + '@types/estree': 1.0.9 + optionalDependencies: + '@napi-rs/lzma-linux-x64-gnu': 1.5.1 + '@rollup/rollup-android-arm-eabi': 4.62.4 + '@rollup/rollup-android-arm64': 4.62.4 + '@rollup/rollup-darwin-arm64': 4.62.4 + '@rollup/rollup-darwin-x64': 4.62.4 + '@rollup/rollup-freebsd-arm64': 4.62.4 + '@rollup/rollup-freebsd-x64': 4.62.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.62.4 + '@rollup/rollup-linux-arm-musleabihf': 4.62.4 + '@rollup/rollup-linux-arm64-gnu': 4.62.4 + '@rollup/rollup-linux-arm64-musl': 4.62.4 + '@rollup/rollup-linux-loong64-gnu': 4.62.4 + '@rollup/rollup-linux-loong64-musl': 4.62.4 + '@rollup/rollup-linux-ppc64-gnu': 4.62.4 + '@rollup/rollup-linux-ppc64-musl': 4.62.4 + '@rollup/rollup-linux-riscv64-gnu': 4.62.4 + '@rollup/rollup-linux-riscv64-musl': 4.62.4 + '@rollup/rollup-linux-s390x-gnu': 4.62.4 + '@rollup/rollup-linux-x64-gnu': 4.62.4 + '@rollup/rollup-linux-x64-musl': 4.62.4 + '@rollup/rollup-openbsd-x64': 4.62.4 + '@rollup/rollup-openharmony-arm64': 4.62.4 + '@rollup/rollup-win32-arm64-msvc': 4.62.4 + '@rollup/rollup-win32-ia32-msvc': 4.62.4 + '@rollup/rollup-win32-x64-gnu': 4.62.4 + '@rollup/rollup-win32-x64-msvc': 4.62.4 + fsevents: 2.3.3 + + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + + rxjs@7.8.1: + dependencies: + tslib: 2.8.1 + + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + scheduler@0.27.0: {} + + schema-utils@3.3.0: + dependencies: + '@types/json-schema': 7.0.15 + ajv: 6.15.0 + ajv-keywords: 3.5.2(ajv@6.15.0) + + schema-utils@4.3.3: + dependencies: + '@types/json-schema': 7.0.15 + ajv: 8.20.0 + ajv-formats: 2.1.1(ajv@8.20.0) + ajv-keywords: 5.1.0(ajv@8.20.0) + + semver@7.8.5: {} + + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.3.0 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + + sharp@0.35.0: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.35.0 + '@img/sharp-darwin-x64': 0.35.0 + '@img/sharp-freebsd-wasm32': 0.35.0 + '@img/sharp-libvips-darwin-arm64': 1.3.0 + '@img/sharp-libvips-darwin-x64': 1.3.0 + '@img/sharp-libvips-linux-arm': 1.3.0 + '@img/sharp-libvips-linux-arm64': 1.3.0 + '@img/sharp-libvips-linux-ppc64': 1.3.0 + '@img/sharp-libvips-linux-riscv64': 1.3.0 + '@img/sharp-libvips-linux-s390x': 1.3.0 + '@img/sharp-libvips-linux-x64': 1.3.0 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.0 + '@img/sharp-libvips-linuxmusl-x64': 1.3.0 + '@img/sharp-linux-arm': 0.35.0 + '@img/sharp-linux-arm64': 0.35.0 + '@img/sharp-linux-ppc64': 0.35.0 + '@img/sharp-linux-riscv64': 0.35.0 + '@img/sharp-linux-s390x': 0.35.0 + '@img/sharp-linux-x64': 0.35.0 + '@img/sharp-linuxmusl-arm64': 0.35.0 + '@img/sharp-linuxmusl-x64': 0.35.0 + '@img/sharp-webcontainers-wasm32': 0.35.0 + '@img/sharp-win32-arm64': 0.35.0 + '@img/sharp-win32-ia32': 0.35.0 + '@img/sharp-win32-x64': 0.35.0 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + siginfo@2.0.0: {} + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + source-map-js@1.2.1: {} + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + source-map@0.7.4: {} + + split2@4.2.0: {} + + stackback@0.0.2: {} + + statuses@2.0.2: {} + + std-env@3.10.0: {} + + streamsearch@1.1.0: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.2.0 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + + strip-bom@3.0.0: {} + + strip-literal@3.1.0: + dependencies: + js-tokens: 9.0.1 + + strtok3@10.3.5: + dependencies: + '@tokenizer/token': 0.3.0 + + styled-jsx@5.1.6(react@19.2.8): + dependencies: + client-only: 0.0.1 + react: 19.2.8 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + symbol-observable@4.0.0: {} + + tapable@2.3.3: {} + + terser-webpack-plugin@5.6.1(webpack@5.106.2): + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + jest-worker: 27.5.1 + schema-utils: 4.3.3 + terser: 5.49.1 + webpack: 5.106.2 + + terser@5.49.1: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.18.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + test-exclude@7.0.2: + dependencies: + '@istanbuljs/schema': 0.1.6 + glob: 10.5.0 + minimatch: 10.2.6 + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 + + tinypool@1.1.1: {} + + tinyrainbow@2.0.0: {} + + tinyspy@4.0.4: {} + + toidentifier@1.0.1: {} + + token-types@6.1.2: + dependencies: + '@borewit/text-codec': 0.2.2 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + + tsconfig-paths-webpack-plugin@4.2.0: + dependencies: + chalk: 4.1.2 + enhanced-resolve: 5.24.5 + tapable: 2.3.3 + tsconfig-paths: 4.2.0 + + tsconfig-paths@4.2.0: + dependencies: + json5: 2.2.3 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.1: {} + + tsx@4.23.5: + dependencies: + esbuild: 0.28.1 + optionalDependencies: + fsevents: 2.3.3 + + turbo@2.10.8: + optionalDependencies: + '@turbo/darwin-64': 2.10.8 + '@turbo/darwin-arm64': 2.10.8 + '@turbo/linux-64': 2.10.8 + '@turbo/linux-arm64': 2.10.8 + '@turbo/windows-64': 2.10.8 + '@turbo/windows-arm64': 2.10.8 + + 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 + media-typer: 1.1.1 + mime-types: 3.0.2 + + typedarray@0.0.6: {} + + typescript@5.9.3: {} + + uid@2.0.2: + dependencies: + '@lukeed/csprng': 1.1.0 + + uint8array-extras@1.5.0: {} + + undici-types@7.18.2: {} + + universalify@2.0.1: {} + + unpipe@1.0.0: {} + + update-browserslist-db@1.2.3(browserslist@4.28.7): + dependencies: + browserslist: 4.28.7 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + vary@1.1.2: {} + + vite-node@3.2.4(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5): + dependencies: + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.3.6(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vite@7.3.6(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5): + dependencies: + esbuild: 0.28.1 + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 + postcss: 8.5.23 + rollup: 4.62.4 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 24.13.3 + fsevents: 2.3.3 + terser: 5.49.1 + tsx: 4.23.5 + + vitest@3.2.7(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5): + dependencies: + '@types/chai': 5.2.3 + '@vitest/expect': 3.2.7 + '@vitest/mocker': 3.2.7(vite@7.3.6(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5)) + '@vitest/pretty-format': 3.2.7 + '@vitest/runner': 3.2.7 + '@vitest/snapshot': 3.2.7 + '@vitest/spy': 3.2.7 + '@vitest/utils': 3.2.7 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.4.0 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.5 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.17 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.3.6(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5) + vite-node: 3.2.4(@types/node@24.13.3)(terser@5.49.1)(tsx@4.23.5) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 24.13.3 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + watchpack@2.5.2: + dependencies: + graceful-fs: 4.2.11 + + wcwidth@1.0.1: + dependencies: + defaults: 1.0.4 + + webpack-node-externals@3.0.0: {} + + webpack-sources@3.5.1: {} + + webpack@5.106.2: + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.9 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.18.0 + acorn-import-phases: 1.0.4(acorn@8.18.0) + browserslist: 4.28.7 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.24.5 + es-module-lexer: 2.3.1 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + loader-runner: 4.3.2 + mime-db: 1.54.0 + neo-async: 2.6.2 + schema-utils: 4.3.3 + tapable: 2.3.3 + terser-webpack-plugin: 5.6.1(webpack@5.106.2) + watchpack: 2.5.2 + webpack-sources: 3.5.1 + transitivePeerDependencies: + - '@minify-html/node' + - '@swc/core' + - '@swc/css' + - '@swc/html' + - clean-css + - cssnano + - csso + - esbuild + - html-minifier-terser + - lightningcss + - postcss + - uglify-js + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 + + wrappy@1.0.2: {} + + xtend@4.0.2: {} + + yargs-parser@21.1.1: {} + + yoctocolors-cjs@2.1.3: {} diff --git a/product/capabilities.json b/product/capabilities.json index 289ea1e7..ec1f5829 100644 --- a/product/capabilities.json +++ b/product/capabilities.json @@ -723,6 +723,47 @@ "path": "apps/ai-service/src/no-silent-mutation.integration.test.ts" } ] + }, + { + "id": "quality.ai-audit-assurance", + "outcome": "Acquirers and operators can verify that the AI audit boundary is fully documented, exhaustively tested, and governed by current standards.", + "target_maturity": "production", + "customer_impact": 4, + "risk": 5, + "acquisition_impact": 5, + "effort": 3, + "dependencies": [ + "ai.auditable-proposals", + "automation.commercial-readiness-loop" + ], + "tracking_issue": 107, + "evidence": [ + { + "maturity": "prototype", + "kind": "implementation", + "mode": "exists", + "path": "apps/ai-service/vitest.config.ts" + }, + { + "maturity": "usable", + "kind": "test", + "mode": "exists", + "path": "apps/ai-service/src/docstring-coverage.test.ts" + }, + { + "maturity": "production", + "kind": "implementation", + "mode": "contains", + "path": "apps/ai-service/vitest.config.ts", + "value": "statements: 100" + }, + { + "maturity": "production", + "kind": "documentation", + "mode": "exists", + "path": "docs/operations/ai-proposal-audit-assurance.md" + } + ] } ] } diff --git a/turbo.json b/turbo.json index 2d3e4d95..f99a2fb5 100644 --- a/turbo.json +++ b/turbo.json @@ -2,6 +2,7 @@ "$schema": "https://turbo.build/schema.json", "globalEnv": [ "AI_DATABASE_URL", + "AI_TEST_DATABASE_URL", "HABIT_DATABASE_URL", "IDENTITY_DATABASE_URL", "NOTIFICATION_DATABASE_URL",