diff --git a/.github/workflows/examples-integration.yaml b/.github/workflows/examples-integration.yaml new file mode 100644 index 000000000..418e9396e --- /dev/null +++ b/.github/workflows/examples-integration.yaml @@ -0,0 +1,24 @@ +name: Examples Integration +on: + pull_request: + branches: [ main, v1 ] + paths: + - 'examples/**' + - 'graphql/codegen/**' + workflow_dispatch: + +jobs: + examples-types: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '20' + - uses: pnpm/action-setup@v2 + with: + version: 10 + - run: pnpm install + - name: Build codegen and dependencies + run: pnpm run build + - run: pnpm -r --filter @constructive-io/examples-codegen-integration run test:codegen diff --git a/CLAUDE.md b/CLAUDE.md index 907fe7cd1..776c240c3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,33 +5,22 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Build & Development Commands ```bash -# Install dependencies -pnpm install - -# Build all packages -pnpm build - -# Build all packages (dev mode - faster, no optimizations) -pnpm build:dev - -# Lint all packages (auto-fix enabled) -pnpm lint - -# Clean build artifacts -pnpm clean - -# Update dependencies interactively -pnpm deps +pnpm install # Install dependencies +pnpm build # Build all packages +pnpm build:dev # Build all packages (dev mode - faster, no optimizations) +pnpm lint # Lint all packages (auto-fix enabled) +pnpm clean # Clean build artifacts +pnpm deps # Update dependencies interactively (pnpm up -r -i -L) ``` ### Per-Package Commands -Navigate to any package directory (e.g., `cd pgpm/cli`) and run: +From any package directory (e.g., `cd pgpm/cli`): ```bash -pnpm build # Build the package +pnpm build # Build the package (uses makage) pnpm lint # Lint with auto-fix -pnpm test # Run tests +pnpm test # Run tests (Jest) pnpm test:watch # Run tests in watch mode pnpm dev # Run in development mode (where available) ``` @@ -41,54 +30,74 @@ pnpm dev # Run in development mode (where available) ```bash cd packages/cli pnpm test -- path/to/test.test.ts -# or with pattern matching: pnpm test -- --testNamePattern="test name pattern" ``` +### Publishing + +Lerna with independent versioning and conventional commits. Publishing only from `main` branch: + +```bash +npx lerna version # Bump versions +npx lerna publish # Publish to npm +``` + ## Project Architecture -This is a **pnpm monorepo** using Lerna for versioning/publishing. The workspace is organized into domain-specific directories: +A **pnpm monorepo** with Lerna for versioning. PostgreSQL-first framework: design your database schema, manage it with pgpm, and get a production-ready GraphQL API automatically via PostGraphile. + +### Data Flow + +``` +PostgreSQL (schema + RLS policies, managed by pgpm migrations) + ↓ +PostGraphile (graphql/server + graphile/* plugins) + ↓ +GraphQL Schema (auto-generated from database) + ↓ +graphql/codegen (--react-query mode OR --orm mode) + ↓ +React Query Hooks or Prisma-like ORM Client +``` -### Core Package Groups +### Workspace Groups | Directory | Purpose | |-----------|---------| -| `pgpm/` | PostgreSQL Package Manager - CLI, core engine, types | -| `graphql/` | GraphQL layer - server, codegen, React hooks, testing | -| `graphile/` | PostGraphile plugins - filters, i18n, meta-schema, PostGIS | -| `postgres/` | PostgreSQL utilities - introspection, testing, seeding, AST | -| `packages/` | Shared utilities - CLI, ORM, query builder | -| `uploads/` | File streaming - S3, ETags, content-type detection | -| `jobs/` | Job scheduling and worker infrastructure | +| `pgpm/` | PostgreSQL Package Manager - CLI (`pgpm`), core engine, types, env, logger | +| `graphql/` | GraphQL layer - server, codegen, query builder, explorer, AST utilities | +| `graphile/` | PostGraphile plugins - filters, i18n, meta-schema, PostGIS, search, uploads, settings | +| `postgres/` | PostgreSQL utilities - introspection, testing (pgsql-test), seeding, AST, query context | +| `packages/` | Shared utilities - CLI (`cnc`), ORM base, query builder, server utils, client | +| `uploads/` | File streaming - S3/MinIO, ETags, content-type detection, UUID hashing | +| `jobs/` | Knative job scheduling - worker, scheduler, service, functions | +| `functions/` | Knative cloud functions (e.g., send-email-link) | -### Key Packages +### Key Packages & CLIs -**pgpm (PostgreSQL Package Manager)** -- `pgpm/cli` - Main CLI tool (`pgpm` command) -- `pgpm/core` - Migration engine, dependency resolution, deployment +**`pgpm` CLI** (`pgpm/cli`) - PostgreSQL Package Manager. Commands: `init`, `add`, `deploy`, `revert`, `verify`, `plan`, `install`, `export`, `docker`, `dump`, `tag`. Manages SQL migrations in Sqitch-compatible format with dependency resolution. -**GraphQL Stack** -- `graphql/server` - Express + PostGraphile API server -- `graphql/codegen` - SDK generator (React Query hooks or Prisma-like ORM) -- `graphql/query` - Fluent GraphQL query builder +**`cnc` CLI** (`packages/cli`, binary: `cnc` or `constructive`) - Full dev toolkit. Commands: `server` (start PostGraphile), `explorer` (GraphiQL UI), `codegen` (generate SDK), `get-graphql-schema`, `jobs`, `context`, `auth`, `execute`. -**Testing Infrastructure** -- `postgres/pgsql-test` - Isolated PostgreSQL test environments with transaction rollback -- `graphile/graphile-test` - GraphQL testing utilities +**`graphql/codegen`** - Generates type-safe clients from GraphQL schema or endpoint: +- `--react-query` mode: TanStack Query v5 hooks with query key factories +- `--orm` mode: Prisma-like fluent API with `InferSelectResult` type inference, discriminated union error handling (`.unwrap()`, `.unwrapOr()`) +- Sources: GraphQL endpoint URL, .graphql schema file, or direct database introspection -### Testing Pattern +**`graphql/server`** - Express + PostGraphile. Supports multi-endpoint routing via subdomain/host detection (schema builder with app-public/auth/admin sub-endpoints). Uses `LISTEN/NOTIFY` for schema cache invalidation. -Tests use `pgsql-test` for database testing with per-test transaction rollback: +**`graphile/graphile-settings`** - Centralizes all PostGraphile plugin config: connection filters, full-text search, PostGIS, i18n, meta-schema, many-to-many, search, upload plugin. Single `getGraphileSettings(opts)` entry point. -```typescript -import { getConnections } from 'pgsql-test'; +**`packages/query-builder`** - Fluent SQL query builder for SELECT/INSERT/UPDATE/DELETE with JOINs, WHERE, GROUP BY. Schema-qualified tables. -let db, teardown; +### Testing Infrastructure -beforeAll(async () => { - ({ db, teardown } = await getConnections()); -}); +**`postgres/pgsql-test`** - Isolated PostgreSQL test environments with per-test transaction rollback: +```typescript +import { getConnections } from 'pgsql-test'; +let db, teardown; +beforeAll(async () => ({ db, teardown } = await getConnections())); beforeEach(() => db.beforeEach()); afterEach(() => db.afterEach()); afterAll(() => teardown()); @@ -100,26 +109,35 @@ test('example', async () => { }); ``` +**`graphile/graphile-test`** - GraphQL testing with PostGraphile snapshot support. + +### Job System + +Background jobs use Knative: jobs are added to `app_jobs.jobs` table → `knative-job-worker` polls and picks up → POSTs to Knative function URL → function executes (e.g., send email) → returns status. + ### Database Configuration -Tests require PostgreSQL. Standard PG environment variables: -- `PGHOST` (default: localhost) -- `PGPORT` (default: 5432) -- `PGUSER` (default: postgres) -- `PGPASSWORD` (default: password) +Tests require PostgreSQL. Standard PG env vars: +- `PGHOST` (default: localhost), `PGPORT` (default: 5432) +- `PGUSER` (default: postgres), `PGPASSWORD` (default: password) For S3/MinIO tests: `MINIO_ENDPOINT`, `AWS_ACCESS_KEY`, `AWS_SECRET_KEY`, `AWS_REGION` -### Build System +## Build System -- Uses `makage` for TypeScript compilation (handles both CJS and ESM output) -- Jest with ts-jest for testing -- ESLint with TypeScript support -- Each package has its own `tsconfig.json` extending root config +- **makage** compiles TypeScript to both CJS and ESM, outputs to `dist/` +- `makage build --dev` for faster dev builds +- Some packages use `copyfiles` for non-TS assets (SQL files, templates) +- Jest with `ts-jest` preset per-package (`jest.config.js` in each package) -### Code Conventions +## Code Conventions -- TypeScript with `strict: true` (but `strictNullChecks: false`) -- Target: ES2022, Module: CommonJS -- Packages publish to npm from `dist/` directory +- TypeScript with `strict: true` but `strictNullChecks: false` +- Target: ES2022, Module: CommonJS, ModuleResolution: node +- 2-space indent, single quotes, semicolons required, no trailing commas +- Imports auto-sorted by `simple-import-sort`, unused imports auto-removed +- `@typescript-eslint/no-explicit-any`: allowed (turned off) +- Unused var pattern: prefix with `_` (e.g., `_unused`) - Workspace dependencies use `workspace:^` protocol +- Packages publish from `dist/` directory +- GraphQL pinned to `15.10.1` via overrides diff --git a/examples/codegen-integration/.gitignore b/examples/codegen-integration/.gitignore new file mode 100644 index 000000000..d3db8f9b1 --- /dev/null +++ b/examples/codegen-integration/.gitignore @@ -0,0 +1 @@ +src/generated/ diff --git a/examples/codegen-integration/codegen.config.ts b/examples/codegen-integration/codegen.config.ts new file mode 100644 index 000000000..48301d8b4 --- /dev/null +++ b/examples/codegen-integration/codegen.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from "@constructive-io/graphql-codegen"; + +export default defineConfig({ + endpoint: "http://example.local/graphql", // not used for fixture run + output: "src/generated", + reactQuery: true, + orm: true, + codegen: { + maxFieldDepth: 2, + skipQueryField: true + }, + // Use the example schema fixtures baked into the repo + schemaFile: "../../graphql/codegen/examples/example.schema.graphql" +}); diff --git a/examples/codegen-integration/package.json b/examples/codegen-integration/package.json new file mode 100644 index 000000000..d7990a228 --- /dev/null +++ b/examples/codegen-integration/package.json @@ -0,0 +1,24 @@ +{ + "name": "@constructive-io/examples-codegen-integration", + "version": "0.0.0", + "private": true, + "scripts": { + "codegen": "tsx scripts/codegen-runner.ts", + "test:types": "pnpm run codegen && tsc --noEmit", + "test:codegen": "pnpm run codegen" + }, + "dependencies": { + "@0no-co/graphql.web": "^1.2.0", + "@tanstack/react-query": "^5.90.20", + "gql-ast": "workspace:^", + "graphql": "15.10.1", + "react": "^19.2.3", + "react-dom": "^19.2.3" + }, + "devDependencies": { + "@constructive-io/graphql-codegen": "workspace:^", + "@constructive-io/graphql-types": "workspace:^", + "tsx": "^4.20.3", + "typescript": "^5.1.6" + } +} diff --git a/examples/codegen-integration/scripts/codegen-runner.ts b/examples/codegen-integration/scripts/codegen-runner.ts new file mode 100644 index 000000000..1c4f62066 --- /dev/null +++ b/examples/codegen-integration/scripts/codegen-runner.ts @@ -0,0 +1,22 @@ +import path from 'path'; +import { generate } from '../../../graphql/codegen/src/core/generate'; + +const root = path.resolve(__dirname, '..'); + +async function run() { + const result = await generate({ + schemaFile: path.resolve(root, '../../graphql/codegen/examples/example.schema.graphql'), + output: path.resolve(root, 'src/generated'), + reactQuery: true, + orm: true + }); + + if (!result.success) { + console.error(result.message); + process.exit(1); + } + + console.log(result.message); +} + +run(); diff --git a/examples/codegen-integration/src/index.ts b/examples/codegen-integration/src/index.ts new file mode 100644 index 000000000..c41f590cc --- /dev/null +++ b/examples/codegen-integration/src/index.ts @@ -0,0 +1,2 @@ +// Placeholder file so tsc has something to include +export {}; diff --git a/examples/codegen-integration/tsconfig.json b/examples/codegen-integration/tsconfig.json new file mode 100644 index 000000000..48f02b77a --- /dev/null +++ b/examples/codegen-integration/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "jsx": "react-jsx", + "skipLibCheck": true, + "noEmit": true, + "baseUrl": ".", + "paths": {} + }, + "include": ["src", "codegen.config.ts"] +} diff --git a/functions/send-email-link/package.json b/functions/send-email-link/package.json index 86e6d7a48..a6ab70cd9 100644 --- a/functions/send-email-link/package.json +++ b/functions/send-email-link/package.json @@ -30,7 +30,7 @@ "build:dev": "makage build --dev" }, "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@constructive-io/knative-job-fn": "workspace:^", diff --git a/functions/simple-email/package.json b/functions/simple-email/package.json index ef497f522..c3c1068f2 100644 --- a/functions/simple-email/package.json +++ b/functions/simple-email/package.json @@ -30,7 +30,7 @@ "build:dev": "makage build --dev" }, "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@constructive-io/knative-job-fn": "workspace:^", diff --git a/graphile/graphile-cache/package.json b/graphile/graphile-cache/package.json index 016a50e25..7d39c7b5e 100644 --- a/graphile/graphile-cache/package.json +++ b/graphile/graphile-cache/package.json @@ -37,7 +37,7 @@ }, "devDependencies": { "@types/pg": "^8.16.0", - "makage": "^0.1.10", + "makage": "^0.1.12", "nodemon": "^3.1.10", "ts-node": "^10.9.2" }, diff --git a/graphile/graphile-i18n/package.json b/graphile/graphile-i18n/package.json index ee59f109a..bf6d28599 100644 --- a/graphile/graphile-i18n/package.json +++ b/graphile/graphile-i18n/package.json @@ -41,7 +41,7 @@ "@types/accept-language-parser": "^1.5.4", "@types/pg": "^8.16.0", "graphile-test": "workspace:^", - "makage": "^0.1.10", + "makage": "^0.1.12", "pgsql-test": "workspace:^" }, "dependencies": { diff --git a/graphile/graphile-many-to-many/package.json b/graphile/graphile-many-to-many/package.json index 0179bc145..ad74376b2 100644 --- a/graphile/graphile-many-to-many/package.json +++ b/graphile/graphile-many-to-many/package.json @@ -44,7 +44,7 @@ "devDependencies": { "graphile-test": "workspace:^", "graphql": "15.10.1", - "makage": "^0.1.10", + "makage": "^0.1.12", "pgsql-test": "workspace:^", "postgraphile": "^4.14.1" } diff --git a/graphile/graphile-meta-schema/package.json b/graphile/graphile-meta-schema/package.json index d1e4bfa94..2b61ef6a5 100644 --- a/graphile/graphile-meta-schema/package.json +++ b/graphile/graphile-meta-schema/package.json @@ -43,7 +43,7 @@ "@graphile-contrib/pg-many-to-many": "^1.0.0", "graphile-test": "workspace:^", "graphql-tag": "2.12.6", - "makage": "^0.1.10", + "makage": "^0.1.12", "pgsql-test": "workspace:^" }, "dependencies": { diff --git a/graphile/graphile-pg-type-mappings/package.json b/graphile/graphile-pg-type-mappings/package.json index e09e59fd6..270adbe1a 100644 --- a/graphile/graphile-pg-type-mappings/package.json +++ b/graphile/graphile-pg-type-mappings/package.json @@ -43,7 +43,7 @@ "graphile-postgis": "workspace:^", "graphile-test": "workspace:^", "graphql-tag": "2.12.6", - "makage": "^0.1.10", + "makage": "^0.1.12", "pgsql-test": "workspace:^" }, "dependencies": { diff --git a/graphile/graphile-plugin-connection-filter-postgis/package.json b/graphile/graphile-plugin-connection-filter-postgis/package.json index 8f508131d..cfa538b03 100644 --- a/graphile/graphile-plugin-connection-filter-postgis/package.json +++ b/graphile/graphile-plugin-connection-filter-postgis/package.json @@ -54,7 +54,7 @@ "@types/pg": "^8.16.0", "graphile-test": "workspace:^", "graphql": "15.10.1", - "makage": "^0.1.10", + "makage": "^0.1.12", "pg": "^8.17.1", "pgsql-test": "workspace:^", "postgraphile": "^4.14.1" diff --git a/graphile/graphile-plugin-connection-filter/package.json b/graphile/graphile-plugin-connection-filter/package.json index 236b3b306..abbd9e249 100644 --- a/graphile/graphile-plugin-connection-filter/package.json +++ b/graphile/graphile-plugin-connection-filter/package.json @@ -52,7 +52,7 @@ "@graphile-contrib/pg-simplify-inflector": "^6.1.0", "@types/pg": "^8.16.0", "graphile-test": "workspace:^", - "makage": "^0.1.10", + "makage": "^0.1.12", "pg": "^8.17.1", "pgsql-test": "workspace:^" } diff --git a/graphile/graphile-plugin-fulltext-filter/package.json b/graphile/graphile-plugin-fulltext-filter/package.json index b851420a2..03a22c7a7 100644 --- a/graphile/graphile-plugin-fulltext-filter/package.json +++ b/graphile/graphile-plugin-fulltext-filter/package.json @@ -52,7 +52,7 @@ "devDependencies": { "graphile-test": "workspace:^", "graphql": "15.10.1", - "makage": "^0.1.10", + "makage": "^0.1.12", "pgsql-test": "workspace:^" } } diff --git a/graphile/graphile-postgis/package.json b/graphile/graphile-postgis/package.json index 8eddf16b8..7fd679af1 100644 --- a/graphile/graphile-postgis/package.json +++ b/graphile/graphile-postgis/package.json @@ -41,7 +41,7 @@ "devDependencies": { "@types/geojson": "^7946.0.14", "graphile-test": "workspace:^", - "makage": "^0.1.10", + "makage": "^0.1.12", "pgsql-test": "workspace:^" }, "dependencies": { diff --git a/graphile/graphile-query/package.json b/graphile/graphile-query/package.json index 5eff113a3..9c84686b4 100644 --- a/graphile/graphile-query/package.json +++ b/graphile/graphile-query/package.json @@ -35,7 +35,7 @@ }, "devDependencies": { "@types/pg": "^8.16.0", - "makage": "^0.1.10" + "makage": "^0.1.12" }, "keywords": [ "graphql", diff --git a/graphile/graphile-search-plugin/package.json b/graphile/graphile-search-plugin/package.json index e2c29b191..0afe09992 100644 --- a/graphile/graphile-search-plugin/package.json +++ b/graphile/graphile-search-plugin/package.json @@ -43,7 +43,7 @@ "graphile-plugin-fulltext-filter": "workspace:^", "graphile-simple-inflector": "workspace:^", "graphile-test": "workspace:^", - "makage": "^0.1.10", + "makage": "^0.1.12", "pgsql-test": "workspace:^" }, "dependencies": { diff --git a/graphile/graphile-settings/package.json b/graphile/graphile-settings/package.json index 71afd9a4b..2a09516e8 100644 --- a/graphile/graphile-settings/package.json +++ b/graphile/graphile-settings/package.json @@ -60,7 +60,7 @@ "@types/express": "^5.0.6", "@types/pg": "^8.16.0", "@types/request-ip": "^0.0.41", - "makage": "^0.1.10", + "makage": "^0.1.12", "nodemon": "^3.1.10", "ts-node": "^10.9.2" }, diff --git a/graphile/graphile-simple-inflector/package.json b/graphile/graphile-simple-inflector/package.json index 17210ad3f..7e7d32f0f 100644 --- a/graphile/graphile-simple-inflector/package.json +++ b/graphile/graphile-simple-inflector/package.json @@ -42,7 +42,7 @@ "devDependencies": { "graphile-test": "workspace:^", "graphql-tag": "2.12.6", - "makage": "^0.1.10", + "makage": "^0.1.12", "pgsql-test": "workspace:^" }, "dependencies": { diff --git a/graphile/graphile-sql-expression-validator/package.json b/graphile/graphile-sql-expression-validator/package.json index e6c15755b..589f9f7e8 100644 --- a/graphile/graphile-sql-expression-validator/package.json +++ b/graphile/graphile-sql-expression-validator/package.json @@ -42,7 +42,7 @@ "url": "https://github.com/constructive-io/constructive/issues" }, "devDependencies": { - "makage": "^0.1.10", + "makage": "^0.1.12", "ts-jest": "^29.4.6" }, "dependencies": { diff --git a/graphile/graphile-test/package.json b/graphile/graphile-test/package.json index e7ffd005e..06638214e 100644 --- a/graphile/graphile-test/package.json +++ b/graphile/graphile-test/package.json @@ -31,7 +31,7 @@ "devDependencies": { "@types/pg": "^8.16.0", "graphql-tag": "2.12.6", - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@constructive-io/graphql-env": "workspace:^", diff --git a/graphile/graphile-upload-plugin/package.json b/graphile/graphile-upload-plugin/package.json index 18ed175cd..327cd0a8b 100644 --- a/graphile/graphile-upload-plugin/package.json +++ b/graphile/graphile-upload-plugin/package.json @@ -45,7 +45,7 @@ "@types/pg": "^8.16.0", "graphile-test": "workspace:^", "graphql-tag": "^2.12.6", - "makage": "^0.1.10", + "makage": "^0.1.12", "pgsql-test": "workspace:^", "ts-jest": "^29.4.6" }, diff --git a/graphql/codegen/AGENTS.md b/graphql/codegen/AGENTS.md new file mode 100644 index 000000000..8c0ab6a5f --- /dev/null +++ b/graphql/codegen/AGENTS.md @@ -0,0 +1,32 @@ +# Code Generation Rules + +## 1. Only AST-based code generation + +All per-schema/per-table code generation MUST use Babel AST (`@babel/types` + `generateCode()`). +Never use `lines.push()`, string concatenation, or template literals to build generated TypeScript code. + +Reference implementations: +- `src/core/codegen/orm/model-generator.ts` — per-table ORM model classes +- `src/core/codegen/orm/client-generator.ts` — createClient factory +- `src/core/codegen/orm/custom-ops-generator.ts` — custom query/mutation operations + +## 2. Never any string-based concatenation + +No `lines.push(...)`, no backtick template literals containing code, no string `+` operators +for building generated source files. If you find yourself writing `lines.push(\`import ...\`)`, +stop and use `t.importDeclaration(...)` instead. + +## 3. Giant templates must be actual files that get copied + +Static runtime code that does not vary per-schema belongs in `src/core/codegen/templates/` +as real `.ts` files. These are read at codegen time via `readTemplateFile()` and written +to the output directory with only the header replaced. + +This gives you: +- Syntax highlighting and IDE support while editing templates +- A clear boundary between "code that generates code" and "code that IS the output" + +Reference implementations: +- `src/core/codegen/templates/orm-client.ts` +- `src/core/codegen/templates/query-builder.ts` +- `src/core/codegen/templates/select-types.ts` diff --git a/graphql/codegen/examples/example.schema.graphql b/graphql/codegen/examples/example.schema.graphql new file mode 100644 index 000000000..1bba02d5c --- /dev/null +++ b/graphql/codegen/examples/example.schema.graphql @@ -0,0 +1,593 @@ +"""A universally unique identifier as defined by [RFC 4122](https://tools.ietf.org/html/rfc4122).""" +scalar UUID + +""" +A point in time as described by the [ISO +8601](https://en.wikipedia.org/wiki/ISO_8601) standard. May or may not include a timezone. +""" +scalar Datetime + +"""A location as described by the [GeoJSON](https://geojson.org/) format.""" +scalar JSON + +"""A string representing a cursor for pagination.""" +scalar Cursor + +"""The root query type.""" +type Query { + """Reads and enables pagination through a set of `User`.""" + users( + first: Int + last: Int + offset: Int + before: Cursor + after: Cursor + orderBy: [UsersOrderBy!] = [PRIMARY_KEY_ASC] + filter: UserFilter + condition: UserCondition + ): UsersConnection + + """Reads a single `User` using its globally unique `ID`.""" + user(id: UUID!): User + + """Reads and enables pagination through a set of `Post`.""" + posts( + first: Int + last: Int + offset: Int + before: Cursor + after: Cursor + orderBy: [PostsOrderBy!] = [PRIMARY_KEY_ASC] + filter: PostFilter + condition: PostCondition + ): PostsConnection + + """Reads a single `Post` using its globally unique `ID`.""" + post(id: UUID!): Post + + """Reads and enables pagination through a set of `Comment`.""" + comments( + first: Int + last: Int + offset: Int + before: Cursor + after: Cursor + orderBy: [CommentsOrderBy!] = [PRIMARY_KEY_ASC] + filter: CommentFilter + ): CommentsConnection + + """Reads a single `Comment` using its globally unique `ID`.""" + comment(id: UUID!): Comment + + """Reads and enables pagination through a set of `Tag`.""" + tags( + first: Int + last: Int + offset: Int + before: Cursor + after: Cursor + orderBy: [TagsOrderBy!] = [PRIMARY_KEY_ASC] + ): TagsConnection + + """The currently authenticated user.""" + currentUser: User + + """Search users by name or email.""" + searchUsers(query: String!): [User!] +} + +"""The root mutation type.""" +type Mutation { + """Creates a single `User`.""" + createUser(input: CreateUserInput!): CreateUserPayload + + """Updates a single `User` using its globally unique `ID`.""" + updateUser(input: UpdateUserInput!): UpdateUserPayload + + """Deletes a single `User` using its globally unique `ID`.""" + deleteUser(input: DeleteUserInput!): DeleteUserPayload + + """Creates a single `Post`.""" + createPost(input: CreatePostInput!): CreatePostPayload + + """Updates a single `Post` using its globally unique `ID`.""" + updatePost(input: UpdatePostInput!): UpdatePostPayload + + """Deletes a single `Post` using its globally unique `ID`.""" + deletePost(input: DeletePostInput!): DeletePostPayload + + """Creates a single `Comment`.""" + createComment(input: CreateCommentInput!): CreateCommentPayload + + """Updates a single `Comment` using its globally unique `ID`.""" + updateComment(input: UpdateCommentInput!): UpdateCommentPayload + + """Deletes a single `Comment` using its globally unique `ID`.""" + deleteComment(input: DeleteCommentInput!): DeleteCommentPayload + + """Creates a single `Tag`.""" + createTag(input: CreateTagInput!): CreateTagPayload + + """Authenticate a user and return a JWT token.""" + login(email: String!, password: String!): LoginPayload + + """Register a new user account.""" + register(username: String!, email: String!, password: String!): RegisterPayload +} + +# ============================================================================ +# Entity Types +# ============================================================================ + +type User { + id: UUID! + username: String! + email: String! + displayName: String + bio: String + role: UserRole! + isActive: Boolean! + createdAt: Datetime! + updatedAt: Datetime + + """Reads and enables pagination through a set of `Post`.""" + posts( + first: Int + last: Int + offset: Int + before: Cursor + after: Cursor + orderBy: [PostsOrderBy!] = [PRIMARY_KEY_ASC] + filter: PostFilter + ): PostsConnection! + + """Reads and enables pagination through a set of `Comment`.""" + comments( + first: Int + last: Int + offset: Int + before: Cursor + after: Cursor + ): CommentsConnection! +} + +type Post { + id: UUID! + title: String! + content: String + slug: String! + status: PostStatus! + authorId: UUID! + publishedAt: Datetime + createdAt: Datetime! + updatedAt: Datetime + + """Reads the `User` that authored this post.""" + author: User + + """Reads and enables pagination through a set of `Comment`.""" + comments( + first: Int + last: Int + offset: Int + before: Cursor + after: Cursor + ): CommentsConnection! + + """Reads and enables pagination through a set of `Tag`.""" + tags( + first: Int + last: Int + offset: Int + before: Cursor + after: Cursor + ): TagsConnection! +} + +type Comment { + id: UUID! + body: String! + postId: UUID! + authorId: UUID! + createdAt: Datetime! + updatedAt: Datetime + + """The post this comment belongs to.""" + post: Post + + """The user who authored this comment.""" + author: User +} + +type Tag { + id: UUID! + name: String! + slug: String! + createdAt: Datetime! +} + +# ============================================================================ +# Enums +# ============================================================================ + +enum UserRole { + ADMIN + EDITOR + USER + GUEST +} + +enum PostStatus { + DRAFT + PUBLISHED + ARCHIVED +} + +enum UsersOrderBy { + NATURAL + PRIMARY_KEY_ASC + PRIMARY_KEY_DESC + ID_ASC + ID_DESC + USERNAME_ASC + USERNAME_DESC + EMAIL_ASC + EMAIL_DESC + CREATED_AT_ASC + CREATED_AT_DESC +} + +enum PostsOrderBy { + NATURAL + PRIMARY_KEY_ASC + PRIMARY_KEY_DESC + ID_ASC + ID_DESC + TITLE_ASC + TITLE_DESC + CREATED_AT_ASC + CREATED_AT_DESC + PUBLISHED_AT_ASC + PUBLISHED_AT_DESC +} + +enum CommentsOrderBy { + NATURAL + PRIMARY_KEY_ASC + PRIMARY_KEY_DESC + ID_ASC + ID_DESC + CREATED_AT_ASC + CREATED_AT_DESC +} + +enum TagsOrderBy { + NATURAL + PRIMARY_KEY_ASC + PRIMARY_KEY_DESC + ID_ASC + ID_DESC + NAME_ASC + NAME_DESC +} + +# ============================================================================ +# Connection Types +# ============================================================================ + +type UsersConnection { + nodes: [User!]! + edges: [UsersEdge!]! + pageInfo: PageInfo! + totalCount: Int! +} + +type UsersEdge { + node: User! + cursor: Cursor! +} + +type PostsConnection { + nodes: [Post!]! + edges: [PostsEdge!]! + pageInfo: PageInfo! + totalCount: Int! +} + +type PostsEdge { + node: Post! + cursor: Cursor! +} + +type CommentsConnection { + nodes: [Comment!]! + edges: [CommentsEdge!]! + pageInfo: PageInfo! + totalCount: Int! +} + +type CommentsEdge { + node: Comment! + cursor: Cursor! +} + +type TagsConnection { + nodes: [Tag!]! + edges: [TagsEdge!]! + pageInfo: PageInfo! + totalCount: Int! +} + +type TagsEdge { + node: Tag! + cursor: Cursor! +} + +type PageInfo { + hasNextPage: Boolean! + hasPreviousPage: Boolean! + startCursor: Cursor + endCursor: Cursor +} + +# ============================================================================ +# Filter Types +# ============================================================================ + +input UserFilter { + id: UUIDFilter + username: StringFilter + email: StringFilter + role: UserRoleFilter + isActive: BooleanFilter + and: [UserFilter!] + or: [UserFilter!] + not: UserFilter +} + +input PostFilter { + id: UUIDFilter + title: StringFilter + status: PostStatusFilter + authorId: UUIDFilter + and: [PostFilter!] + or: [PostFilter!] + not: PostFilter +} + +input CommentFilter { + id: UUIDFilter + postId: UUIDFilter + authorId: UUIDFilter + and: [CommentFilter!] + or: [CommentFilter!] + not: CommentFilter +} + +input UUIDFilter { + equalTo: UUID + notEqualTo: UUID + in: [UUID!] + notIn: [UUID!] + isNull: Boolean +} + +input StringFilter { + equalTo: String + notEqualTo: String + in: [String!] + notIn: [String!] + includes: String + startsWith: String + endsWith: String + isNull: Boolean +} + +input BooleanFilter { + equalTo: Boolean + notEqualTo: Boolean + isNull: Boolean +} + +input UserRoleFilter { + equalTo: UserRole + notEqualTo: UserRole + in: [UserRole!] + notIn: [UserRole!] +} + +input PostStatusFilter { + equalTo: PostStatus + notEqualTo: PostStatus + in: [PostStatus!] + notIn: [PostStatus!] +} + +# ============================================================================ +# Condition Types +# ============================================================================ + +input UserCondition { + id: UUID + username: String + email: String +} + +input PostCondition { + id: UUID + title: String + authorId: UUID +} + +# ============================================================================ +# Mutation Input Types +# ============================================================================ + +input CreateUserInput { + clientMutationId: String + user: UserInput! +} + +input UserInput { + username: String! + email: String! + displayName: String + bio: String + role: UserRole +} + +input UpdateUserInput { + clientMutationId: String + id: UUID! + patch: UserPatch! +} + +input UserPatch { + username: String + email: String + displayName: String + bio: String + role: UserRole + isActive: Boolean +} + +input DeleteUserInput { + clientMutationId: String + id: UUID! +} + +input CreatePostInput { + clientMutationId: String + post: PostInput! +} + +input PostInput { + title: String! + content: String + slug: String! + status: PostStatus + authorId: UUID! +} + +input UpdatePostInput { + clientMutationId: String + id: UUID! + patch: PostPatch! +} + +input PostPatch { + title: String + content: String + slug: String + status: PostStatus + publishedAt: Datetime +} + +input DeletePostInput { + clientMutationId: String + id: UUID! +} + +input CreateCommentInput { + clientMutationId: String + comment: CommentInput! +} + +input CommentInput { + body: String! + postId: UUID! + authorId: UUID! +} + +input UpdateCommentInput { + clientMutationId: String + id: UUID! + patch: CommentPatch! +} + +input CommentPatch { + body: String +} + +input DeleteCommentInput { + clientMutationId: String + id: UUID! +} + +input CreateTagInput { + clientMutationId: String + tag: TagInput! +} + +input TagInput { + name: String! + slug: String! +} + +# ============================================================================ +# Mutation Payload Types +# ============================================================================ + +type CreateUserPayload { + clientMutationId: String + user: User +} + +type UpdateUserPayload { + clientMutationId: String + user: User +} + +type DeleteUserPayload { + clientMutationId: String + user: User +} + +type CreatePostPayload { + clientMutationId: String + post: Post +} + +type UpdatePostPayload { + clientMutationId: String + post: Post +} + +type DeletePostPayload { + clientMutationId: String + post: Post +} + +type CreateCommentPayload { + clientMutationId: String + comment: Comment +} + +type UpdateCommentPayload { + clientMutationId: String + comment: Comment +} + +type DeleteCommentPayload { + clientMutationId: String + comment: Comment +} + +type CreateTagPayload { + clientMutationId: String + tag: Tag +} + +# ============================================================================ +# Custom Operation Payload Types +# ============================================================================ + +type LoginPayload { + token: String! + user: User! +} + +type RegisterPayload { + token: String! + user: User! +} diff --git a/graphql/codegen/examples/multi-target.config.ts b/graphql/codegen/examples/multi-target.config.ts new file mode 100644 index 000000000..75f3628c0 --- /dev/null +++ b/graphql/codegen/examples/multi-target.config.ts @@ -0,0 +1,15 @@ +import type { GraphQLSDKConfigTarget } from '../src/types/config'; + +/** + * Multi-target example config for graphql-codegen + * + * Usage with CLI flags to select mode: + * tsx src/cli/index.ts --config examples/multi-target.config.ts --react-query + * tsx src/cli/index.ts --config examples/multi-target.config.ts --orm + */ +const config: GraphQLSDKConfigTarget = { + endpoint: 'http://api.localhost:3000/graphql', + output: './examples/output/generated-sdk-public', +}; + +export default config; diff --git a/graphql/codegen/jest.config.js b/graphql/codegen/jest.config.js index 86f911c5d..475aa4db7 100644 --- a/graphql/codegen/jest.config.js +++ b/graphql/codegen/jest.config.js @@ -7,9 +7,9 @@ module.exports = { 'ts-jest', { babelConfig: false, - tsconfig: 'tsconfig.json', - }, - ], + tsconfig: 'tsconfig.json' + } + ] }, transformIgnorePatterns: [`/node_modules/*`], testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$', diff --git a/graphql/codegen/src/__tests__/codegen/__snapshots__/client-generator.test.ts.snap b/graphql/codegen/src/__tests__/codegen/__snapshots__/client-generator.test.ts.snap index 11e9fad8f..383dbaa7f 100644 --- a/graphql/codegen/src/__tests__/codegen/__snapshots__/client-generator.test.ts.snap +++ b/graphql/codegen/src/__tests__/codegen/__snapshots__/client-generator.test.ts.snap @@ -125,14 +125,14 @@ export class FetchAdapter implements GraphQLAdapter { constructor( private endpoint: string, - headers?: Record + headers?: Record, ) { this.headers = headers ?? {}; } async execute( document: string, - variables?: Record + variables?: Record, ): Promise> { const response = await fetch(this.endpoint, { method: 'POST', @@ -151,7 +151,9 @@ export class FetchAdapter implements GraphQLAdapter { return { ok: false, data: null, - errors: [{ message: \`HTTP \${response.status}: \${response.statusText}\` }], + errors: [ + { message: \`HTTP \${response.status}: \${response.statusText}\` }, + ], }; } @@ -204,7 +206,7 @@ export interface OrmClientConfig { export class GraphQLRequestError extends Error { constructor( public readonly errors: GraphQLError[], - public readonly data: unknown = null + public readonly data: unknown = null, ) { const messages = errors.map((e) => e.message).join('; '); super(\`GraphQL Error: \${messages}\`); @@ -222,14 +224,14 @@ export class OrmClient { this.adapter = new FetchAdapter(config.endpoint, config.headers); } else { throw new Error( - 'OrmClientConfig requires either an endpoint or a custom adapter' + 'OrmClientConfig requires either an endpoint or a custom adapter', ); } } async execute( document: string, - variables?: Record + variables?: Record, ): Promise> { return this.adapter.execute(document, variables); } @@ -301,23 +303,26 @@ export interface UpdateArgs { select?: TSelect; } -export interface DeleteArgs { +export type FindOneArgs< + TSelect, + TIdName extends string = 'id', + TId = string, +> = { + select?: TSelect; +} & Record; + +export interface DeleteArgs { where: TWhere; + select?: TSelect; } /** * Recursively validates select objects, rejecting unknown keys. * - * This type ensures that users can only select fields that actually exist - * in the GraphQL schema. It returns \`never\` if any excess keys are found - * at any nesting level, causing a TypeScript compile error. - * - * Why this is needed: - * TypeScript's excess property checking has a quirk where it only catches - * invalid fields when they are the ONLY fields. When mixed with valid fields - * (e.g., \`{ id: true, invalidField: true }\`), the structural typing allows - * the excess property through. This type explicitly checks for and rejects - * such cases. + * NOTE: This type is intentionally NOT used in generated parameter positions + * (conditional types block IDE autocompletion). Parameters use \`S\` directly + * with \`S extends XxxSelect\` constraints, which provides full + * autocompletion via TypeScript's contextual typing. * * @example * // This will cause a type error because 'invalid' doesn't exist: @@ -334,15 +339,29 @@ export type DeepExact = T extends Shape ? { [K in keyof T]: K extends keyof Shape ? T[K] extends { select: infer NS } - ? Shape[K] extends { select?: infer ShapeNS } - ? { select: DeepExact> } - : T[K] + ? Extract extends { + select?: infer ShapeNS; + } + ? DeepExact< + Omit & { + select: DeepExact>; + }, + Extract + > + : never : T[K] : never; } : never : never; +/** + * Enforces exact select shape while keeping contextual typing on \`S extends XxxSelect\`. + * Use this as an intersection in overloads: + * \`{ select: S } & StrictSelect\`. + */ +export type StrictSelect = S extends DeepExact ? {} : never; + /** * Infer result type from select configuration */ diff --git a/graphql/codegen/src/__tests__/codegen/__snapshots__/input-types-generator.test.ts.snap b/graphql/codegen/src/__tests__/codegen/__snapshots__/input-types-generator.test.ts.snap index 523156dd3..816974a38 100644 --- a/graphql/codegen/src/__tests__/codegen/__snapshots__/input-types-generator.test.ts.snap +++ b/graphql/codegen/src/__tests__/codegen/__snapshots__/input-types-generator.test.ts.snap @@ -469,7 +469,17 @@ export interface UpdateCommentInput { export interface DeleteCommentInput { clientMutationId?: string; id: string; -}" +} +// ============ Connection Fields Map ============ +export const connectionFieldsMap = { + "User": { + "posts": "Post", + "comments": "Comment" + }, + "Post": { + "comments": "Comment" + } +} as Record>;" `; exports[`generateInputTypesFile generates complete types file for single table 1`] = ` @@ -785,7 +795,9 @@ export interface UpdateUserInput { export interface DeleteUserInput { clientMutationId?: string; id: string; -}" +} +// ============ Connection Fields Map ============ +export const connectionFieldsMap = {} as Record>;" `; exports[`generateInputTypesFile generates custom input types from TypeRegistry 1`] = ` @@ -1102,6 +1114,8 @@ export interface DeleteUserInput { clientMutationId?: string; id: string; } +// ============ Connection Fields Map ============ +export const connectionFieldsMap = {} as Record>; // ============ Custom Input Types (from schema) ============ export interface LoginInput { email: string; @@ -1430,6 +1444,8 @@ export interface DeleteUserInput { clientMutationId?: string; id: string; } +// ============ Connection Fields Map ============ +export const connectionFieldsMap = {} as Record>; // ============ Custom Input Types (from schema) ============ export interface LoginInput { email: string; @@ -1831,7 +1847,13 @@ export interface UpdateProfileInput { export interface DeleteProfileInput { clientMutationId?: string; id: string; -}" +} +// ============ Connection Fields Map ============ +export const connectionFieldsMap = { + "User": { + "posts": "Post" + } +} as Record>;" `; exports[`generateInputTypesFile generates types with manyToMany relations 1`] = ` @@ -2209,7 +2231,16 @@ export interface UpdateCategoryInput { export interface DeleteCategoryInput { clientMutationId?: string; id: string; -}" +} +// ============ Connection Fields Map ============ +export const connectionFieldsMap = { + "Post": { + "comments": "Comment" + }, + "Category": { + "posts": "Post" + } +} as Record>;" `; exports[`generateInputTypesFile handles empty tables array 1`] = ` @@ -2437,5 +2468,7 @@ export interface UUIDListFilter { anyLessThanOrEqualTo?: string; anyGreaterThan?: string; anyGreaterThanOrEqualTo?: string; -}" +} +// ============ Connection Fields Map ============ +export const connectionFieldsMap = {} as Record>;" `; diff --git a/graphql/codegen/src/__tests__/codegen/__snapshots__/model-generator.test.ts.snap b/graphql/codegen/src/__tests__/codegen/__snapshots__/model-generator.test.ts.snap index dc51d712f..ee27c182a 100644 --- a/graphql/codegen/src/__tests__/codegen/__snapshots__/model-generator.test.ts.snap +++ b/graphql/codegen/src/__tests__/codegen/__snapshots__/model-generator.test.ts.snap @@ -7,18 +7,22 @@ exports[`model-generator generates model with all CRUD methods 1`] = ` * DO NOT EDIT - changes will be overwritten */ import { OrmClient } from "../client"; -import { QueryBuilder, buildFindManyDocument, buildFindFirstDocument, buildCreateDocument, buildUpdateDocument, buildDeleteDocument } from "../query-builder"; -import type { ConnectionResult, FindManyArgs, FindFirstArgs, CreateArgs, UpdateArgs, DeleteArgs, InferSelectResult, DeepExact } from "../select-types"; +import { QueryBuilder, buildFindManyDocument, buildFindFirstDocument, buildFindOneDocument, buildCreateDocument, buildUpdateByPkDocument, buildDeleteByPkDocument } from "../query-builder"; +import type { ConnectionResult, FindManyArgs, FindFirstArgs, CreateArgs, UpdateArgs, DeleteArgs, InferSelectResult, StrictSelect } from "../select-types"; import type { User, UserWithRelations, UserSelect, UserFilter, UsersOrderBy, CreateUserInput, UpdateUserInput, UserPatch } from "../input-types"; +import { connectionFieldsMap } from "../input-types"; export class UserModel { constructor(private client: OrmClient) {} - findMany(args?: FindManyArgs, UserFilter, UsersOrderBy>): QueryBuilder<{ + findMany(args: FindManyArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ users: ConnectionResult>; - }> { + }>; + findMany(args: FindManyArgs) { const { document, variables - } = buildFindManyDocument("User", "users", args?.select, { + } = buildFindManyDocument("User", "users", args.select, { where: args?.where, orderBy: args?.orderBy as string[] | undefined, first: args?.first, @@ -26,7 +30,7 @@ export class UserModel { after: args?.after, before: args?.before, offset: args?.offset - }, "UserFilter", "UsersOrderBy"); + }, "UserFilter", "UsersOrderBy", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "query", @@ -36,17 +40,20 @@ export class UserModel { variables }); } - findFirst(args?: FindFirstArgs, UserFilter>): QueryBuilder<{ + findFirst(args: FindFirstArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ users: { nodes: InferSelectResult[]; }; - }> { + }>; + findFirst(args: FindFirstArgs) { const { document, variables - } = buildFindFirstDocument("User", "users", args?.select, { + } = buildFindFirstDocument("User", "users", args.select, { where: args?.where - }, "UserFilter"); + }, "UserFilter", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "query", @@ -56,15 +63,41 @@ export class UserModel { variables }); } - create(args: CreateArgs, CreateUserInput["user"]>): QueryBuilder<{ + findOne(args: { + id: string; + select: S; + } & StrictSelect): QueryBuilder<{ + user: InferSelectResult | null; + }>; + findOne(args: { + id: string; + select: UserSelect; + }) { + const { + document, + variables + } = buildFindOneDocument("User", "user", args.id, args.select, "id", "UUID!", connectionFieldsMap); + return new QueryBuilder({ + client: this.client, + operation: "query", + operationName: "User", + fieldName: "user", + document, + variables + }); + } + create(args: CreateArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ createUser: { user: InferSelectResult; }; - }> { + }>; + create(args: CreateArgs) { const { document, variables - } = buildCreateDocument("User", "createUser", "user", args.select, args.data, "CreateUserInput"); + } = buildCreateDocument("User", "createUser", "user", args.select, args.data, "CreateUserInput", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -74,17 +107,22 @@ export class UserModel { variables }); } - update(args: UpdateArgs, { + update(args: UpdateArgs): QueryBuilder<{ + }, UserPatch> & { + select: S; + } & StrictSelect): QueryBuilder<{ updateUser: { user: InferSelectResult; }; - }> { + }>; + update(args: UpdateArgs) { const { document, variables - } = buildUpdateDocument("User", "updateUser", "user", args.select, args.where, args.data, "UpdateUserInput"); + } = buildUpdateByPkDocument("User", "updateUser", "user", args.select, args.where.id, args.data, "UpdateUserInput", "id", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -94,19 +132,22 @@ export class UserModel { variables }); } - delete(args: DeleteArgs<{ + delete(args: DeleteArgs<{ id: string; - }>): QueryBuilder<{ + }, S> & { + select: S; + } & StrictSelect): QueryBuilder<{ deleteUser: { - user: { - id: string; - }; + user: InferSelectResult; }; - }> { + }>; + delete(args: DeleteArgs<{ + id: string; + }, UserSelect>) { const { document, variables - } = buildDeleteDocument("User", "deleteUser", "user", args.where, "DeleteUserInput"); + } = buildDeleteByPkDocument("User", "deleteUser", "user", args.where.id, "DeleteUserInput", "id", args.select, connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -126,18 +167,22 @@ exports[`model-generator generates model without update/delete when not availabl * DO NOT EDIT - changes will be overwritten */ import { OrmClient } from "../client"; -import { QueryBuilder, buildFindManyDocument, buildFindFirstDocument, buildCreateDocument, buildUpdateDocument, buildDeleteDocument } from "../query-builder"; -import type { ConnectionResult, FindManyArgs, FindFirstArgs, CreateArgs, UpdateArgs, DeleteArgs, InferSelectResult, DeepExact } from "../select-types"; +import { QueryBuilder, buildFindManyDocument, buildFindFirstDocument, buildFindOneDocument, buildCreateDocument, buildUpdateByPkDocument, buildDeleteByPkDocument } from "../query-builder"; +import type { ConnectionResult, FindManyArgs, FindFirstArgs, CreateArgs, UpdateArgs, DeleteArgs, InferSelectResult, StrictSelect } from "../select-types"; import type { AuditLog, AuditLogWithRelations, AuditLogSelect, AuditLogFilter, AuditLogsOrderBy, CreateAuditLogInput, UpdateAuditLogInput, AuditLogPatch } from "../input-types"; +import { connectionFieldsMap } from "../input-types"; export class AuditLogModel { constructor(private client: OrmClient) {} - findMany(args?: FindManyArgs, AuditLogFilter, AuditLogsOrderBy>): QueryBuilder<{ + findMany(args: FindManyArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ auditLogs: ConnectionResult>; - }> { + }>; + findMany(args: FindManyArgs) { const { document, variables - } = buildFindManyDocument("AuditLog", "auditLogs", args?.select, { + } = buildFindManyDocument("AuditLog", "auditLogs", args.select, { where: args?.where, orderBy: args?.orderBy as string[] | undefined, first: args?.first, @@ -145,7 +190,7 @@ export class AuditLogModel { after: args?.after, before: args?.before, offset: args?.offset - }, "AuditLogFilter", "AuditLogsOrderBy"); + }, "AuditLogFilter", "AuditLogsOrderBy", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "query", @@ -155,17 +200,20 @@ export class AuditLogModel { variables }); } - findFirst(args?: FindFirstArgs, AuditLogFilter>): QueryBuilder<{ + findFirst(args: FindFirstArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ auditLogs: { nodes: InferSelectResult[]; }; - }> { + }>; + findFirst(args: FindFirstArgs) { const { document, variables - } = buildFindFirstDocument("AuditLog", "auditLogs", args?.select, { + } = buildFindFirstDocument("AuditLog", "auditLogs", args.select, { where: args?.where - }, "AuditLogFilter"); + }, "AuditLogFilter", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "query", @@ -175,15 +223,41 @@ export class AuditLogModel { variables }); } - create(args: CreateArgs, CreateAuditLogInput["auditLog"]>): QueryBuilder<{ + findOne(args: { + id: string; + select: S; + } & StrictSelect): QueryBuilder<{ + auditLog: InferSelectResult | null; + }>; + findOne(args: { + id: string; + select: AuditLogSelect; + }) { + const { + document, + variables + } = buildFindOneDocument("AuditLog", "auditLog", args.id, args.select, "id", "UUID!", connectionFieldsMap); + return new QueryBuilder({ + client: this.client, + operation: "query", + operationName: "AuditLog", + fieldName: "auditLog", + document, + variables + }); + } + create(args: CreateArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ createAuditLog: { auditLog: InferSelectResult; }; - }> { + }>; + create(args: CreateArgs) { const { document, variables - } = buildCreateDocument("AuditLog", "createAuditLog", "auditLog", args.select, args.data, "CreateAuditLogInput"); + } = buildCreateDocument("AuditLog", "createAuditLog", "auditLog", args.select, args.data, "CreateAuditLogInput", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -203,18 +277,22 @@ exports[`model-generator handles custom query/mutation names 1`] = ` * DO NOT EDIT - changes will be overwritten */ import { OrmClient } from "../client"; -import { QueryBuilder, buildFindManyDocument, buildFindFirstDocument, buildCreateDocument, buildUpdateDocument, buildDeleteDocument } from "../query-builder"; -import type { ConnectionResult, FindManyArgs, FindFirstArgs, CreateArgs, UpdateArgs, DeleteArgs, InferSelectResult, DeepExact } from "../select-types"; +import { QueryBuilder, buildFindManyDocument, buildFindFirstDocument, buildFindOneDocument, buildCreateDocument, buildUpdateByPkDocument, buildDeleteByPkDocument } from "../query-builder"; +import type { ConnectionResult, FindManyArgs, FindFirstArgs, CreateArgs, UpdateArgs, DeleteArgs, InferSelectResult, StrictSelect } from "../select-types"; import type { Organization, OrganizationWithRelations, OrganizationSelect, OrganizationFilter, OrganizationsOrderBy, CreateOrganizationInput, UpdateOrganizationInput, OrganizationPatch } from "../input-types"; +import { connectionFieldsMap } from "../input-types"; export class OrganizationModel { constructor(private client: OrmClient) {} - findMany(args?: FindManyArgs, OrganizationFilter, OrganizationsOrderBy>): QueryBuilder<{ + findMany(args: FindManyArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ allOrganizations: ConnectionResult>; - }> { + }>; + findMany(args: FindManyArgs) { const { document, variables - } = buildFindManyDocument("Organization", "allOrganizations", args?.select, { + } = buildFindManyDocument("Organization", "allOrganizations", args.select, { where: args?.where, orderBy: args?.orderBy as string[] | undefined, first: args?.first, @@ -222,7 +300,7 @@ export class OrganizationModel { after: args?.after, before: args?.before, offset: args?.offset - }, "OrganizationFilter", "OrganizationsOrderBy"); + }, "OrganizationFilter", "OrganizationsOrderBy", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "query", @@ -232,17 +310,20 @@ export class OrganizationModel { variables }); } - findFirst(args?: FindFirstArgs, OrganizationFilter>): QueryBuilder<{ + findFirst(args: FindFirstArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ allOrganizations: { nodes: InferSelectResult[]; }; - }> { + }>; + findFirst(args: FindFirstArgs) { const { document, variables - } = buildFindFirstDocument("Organization", "allOrganizations", args?.select, { + } = buildFindFirstDocument("Organization", "allOrganizations", args.select, { where: args?.where - }, "OrganizationFilter"); + }, "OrganizationFilter", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "query", @@ -252,15 +333,41 @@ export class OrganizationModel { variables }); } - create(args: CreateArgs, CreateOrganizationInput["organization"]>): QueryBuilder<{ + findOne(args: { + id: string; + select: S; + } & StrictSelect): QueryBuilder<{ + organizationById: InferSelectResult | null; + }>; + findOne(args: { + id: string; + select: OrganizationSelect; + }) { + const { + document, + variables + } = buildFindOneDocument("Organization", "organizationById", args.id, args.select, "id", "UUID!", connectionFieldsMap); + return new QueryBuilder({ + client: this.client, + operation: "query", + operationName: "Organization", + fieldName: "organizationById", + document, + variables + }); + } + create(args: CreateArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ registerOrganization: { organization: InferSelectResult; }; - }> { + }>; + create(args: CreateArgs) { const { document, variables - } = buildCreateDocument("Organization", "registerOrganization", "organization", args.select, args.data, "CreateOrganizationInput"); + } = buildCreateDocument("Organization", "registerOrganization", "organization", args.select, args.data, "CreateOrganizationInput", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -270,17 +377,22 @@ export class OrganizationModel { variables }); } - update(args: UpdateArgs, { + update(args: UpdateArgs): QueryBuilder<{ + }, OrganizationPatch> & { + select: S; + } & StrictSelect): QueryBuilder<{ modifyOrganization: { organization: InferSelectResult; }; - }> { + }>; + update(args: UpdateArgs) { const { document, variables - } = buildUpdateDocument("Organization", "modifyOrganization", "organization", args.select, args.where, args.data, "UpdateOrganizationInput"); + } = buildUpdateByPkDocument("Organization", "modifyOrganization", "organization", args.select, args.where.id, args.data, "UpdateOrganizationInput", "id", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -290,19 +402,22 @@ export class OrganizationModel { variables }); } - delete(args: DeleteArgs<{ + delete(args: DeleteArgs<{ id: string; - }>): QueryBuilder<{ + }, S> & { + select: S; + } & StrictSelect): QueryBuilder<{ removeOrganization: { - organization: { - id: string; - }; + organization: InferSelectResult; }; - }> { + }>; + delete(args: DeleteArgs<{ + id: string; + }, OrganizationSelect>) { const { document, variables - } = buildDeleteDocument("Organization", "removeOrganization", "organization", args.where, "DeleteOrganizationInput"); + } = buildDeleteByPkDocument("Organization", "removeOrganization", "organization", args.where.id, "DeleteOrganizationInput", "id", args.select, connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", diff --git a/graphql/codegen/src/__tests__/codegen/__snapshots__/query-builder.test.ts.snap b/graphql/codegen/src/__tests__/codegen/__snapshots__/query-builder.test.ts.snap new file mode 100644 index 000000000..f679d5605 --- /dev/null +++ b/graphql/codegen/src/__tests__/codegen/__snapshots__/query-builder.test.ts.snap @@ -0,0 +1,227 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`query-builder snapshots findMany document with filter and pagination 1`] = ` +"query UserQuery($where: UserFilter, $orderBy: [UsersOrderBy!], $first: Int) { + users(filter: $where, orderBy: $orderBy, first: $first) { + nodes { + id + name + email + } + totalCount + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } + } +} +" +`; + +exports[`query-builder snapshots findMany document with nested connections via connectionFieldsMap 1`] = ` +"query UserQuery { + users { + nodes { + id + name + posts { + nodes { + id + title + } + totalCount + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } + } + comments { + nodes { + id + } + totalCount + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } + } + } + totalCount + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } + } +} +" +`; + +exports[`query-builder snapshots findMany with deeply nested connections (3 levels) 1`] = ` +"query TestQuery { + users { + nodes { + id + posts { + nodes { + id + title + comments { + nodes { + id + body + } + totalCount + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } + } + } + totalCount + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } + } + } + totalCount + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } + } +} +" +`; + +exports[`query-builder snapshots findMany with mixed connection and singular relations 1`] = ` +"query TestQuery { + users { + nodes { + id + name + profile { + bio + avatar + } + posts { + nodes { + id + title + } + totalCount + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } + } + comments { + nodes { + id + body + } + totalCount + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } + } + } + totalCount + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } + } +} +" +`; + +exports[`query-builder snapshots findMany with nested connection fields 1`] = ` +"query TestQuery { + users { + nodes { + id + name + posts { + nodes { + id + title + body + } + totalCount + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } + } + } + totalCount + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } + } +} +" +`; + +exports[`query-builder snapshots findMany without connectionFieldsMap (no wrapping) 1`] = ` +"query TestQuery { + users { + nodes { + id + name + posts { + id + title + } + } + totalCount + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } + } +} +" +`; + +exports[`query-builder snapshots mutation document 1`] = ` +"mutation CreateUserMutation($input: CreateUserInput!) { + createUser(input: $input) { + user { + id + name + email + } + } +} +" +`; diff --git a/graphql/codegen/src/__tests__/codegen/__snapshots__/react-query-hooks.test.ts.snap b/graphql/codegen/src/__tests__/codegen/__snapshots__/react-query-hooks.test.ts.snap index efafdb00e..b5bbe99d3 100644 --- a/graphql/codegen/src/__tests__/codegen/__snapshots__/react-query-hooks.test.ts.snap +++ b/graphql/codegen/src/__tests__/codegen/__snapshots__/react-query-hooks.test.ts.snap @@ -50,15 +50,17 @@ exports[`Barrel File Generators generateMainBarrel generates main barrel with al * import { useCarsQuery, useCreateCarMutation } from './generated'; * * function MyComponent() { - * const { data, isLoading } = useCarsQuery({ first: 10 }); - * const { mutate } = useCreateCarMutation(); + * const { data, isLoading } = useCarsQuery({ + * selection: { fields: { id: true }, first: 10 }, + * }); + * const { mutate } = useCreateCarMutation({ + * selection: { fields: { id: true } }, + * }); * // ... * } * \`\`\` */ export * from "./client"; -export * from "./types"; -export * from "./schema-types"; export * from "./query-keys"; export * from "./mutation-keys"; export * from "./invalidation"; @@ -90,14 +92,17 @@ exports[`Barrel File Generators generateMainBarrel generates main barrel without * import { useCarsQuery, useCreateCarMutation } from './generated'; * * function MyComponent() { - * const { data, isLoading } = useCarsQuery({ first: 10 }); - * const { mutate } = useCreateCarMutation(); + * const { data, isLoading } = useCarsQuery({ + * selection: { fields: { id: true }, first: 10 }, + * }); + * const { mutate } = useCreateCarMutation({ + * selection: { fields: { id: true } }, + * }); * // ... * } * \`\`\` */ export * from "./client"; -export * from "./types"; export * from "./queries"; export * from "./mutations";" `; @@ -126,15 +131,17 @@ exports[`Barrel File Generators generateMainBarrel generates main barrel without * import { useCarsQuery, useCreateCarMutation } from './generated'; * * function MyComponent() { - * const { data, isLoading } = useCarsQuery({ first: 10 }); - * const { mutate } = useCreateCarMutation(); + * const { data, isLoading } = useCarsQuery({ + * selection: { fields: { id: true }, first: 10 }, + * }); + * const { mutate } = useCreateCarMutation({ + * selection: { fields: { id: true } }, + * }); * // ... * } * \`\`\` */ export * from "./client"; -export * from "./types"; -export * from "./schema-types"; export * from "./queries";" `; @@ -193,32 +200,43 @@ exports[`Custom Mutation Hook Generators generateCustomMutationHook generates cu */ import { useMutation } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { LoginPayload } from "../schema-types"; +import type { UseMutationOptions, UseMutationResult } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; import { customMutationKeys } from "../mutation-keys"; -/** GraphQL mutation document */ -export const loginMutationDocument = \` -mutation LoginMutation($email: String!, $password: String!) { - login(email: $email, password: $password) { - token - } -} -\`; -export interface LoginMutationVariables { - email: string; - password: string; -} -export interface LoginMutationResult { - login: LoginPayload; -} -export function useLoginMutation(options?: Omit, 'mutationFn'>) { +import type { LoginVariables } from "../../orm/mutation"; +import type { LoginPayloadSelect, LoginPayload } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { LoginVariables } from "../../orm/mutation"; +export type { LoginPayloadSelect } from "../../orm/input-types"; +export function useLoginMutation(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; +}, Error, LoginVariables>, "mutationFn">): UseMutationResult<{ + login: InferSelectResult; +}, Error, LoginVariables>; +export function useLoginMutation(params: { + selection: SelectionConfig; +} & Omit, "mutationFn">) { + const args = buildSelectionArgs(params.selection); + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; + void _selection; return useMutation({ mutationKey: customMutationKeys.login(), - mutationFn: (variables: LoginMutationVariables) => execute(loginMutationDocument, variables), - ...options + mutationFn: (variables: LoginVariables) => getClient().mutation.login(variables, { + select: args.select + }).unwrap(), + ...mutationOptions }); -}" +} +" `; exports[`Custom Mutation Hook Generators generateCustomMutationHook generates custom mutation hook with input object argument 1`] = ` @@ -229,31 +247,43 @@ exports[`Custom Mutation Hook Generators generateCustomMutationHook generates cu */ import { useMutation } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { RegisterInput, RegisterPayload } from "../schema-types"; +import type { UseMutationOptions, UseMutationResult } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; import { customMutationKeys } from "../mutation-keys"; -/** GraphQL mutation document */ -export const registerMutationDocument = \` -mutation RegisterMutation($input: RegisterInput!) { - register(input: $input) { - token - } -} -\`; -export interface RegisterMutationVariables { - input: RegisterInput; -} -export interface RegisterMutationResult { - register: RegisterPayload; -} -export function useRegisterMutation(options?: Omit, 'mutationFn'>) { +import type { RegisterVariables } from "../../orm/mutation"; +import type { RegisterPayloadSelect, RegisterPayload } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { RegisterVariables } from "../../orm/mutation"; +export type { RegisterPayloadSelect } from "../../orm/input-types"; +export function useRegisterMutation(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; +}, Error, RegisterVariables>, "mutationFn">): UseMutationResult<{ + register: InferSelectResult; +}, Error, RegisterVariables>; +export function useRegisterMutation(params: { + selection: SelectionConfig; +} & Omit, "mutationFn">) { + const args = buildSelectionArgs(params.selection); + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; + void _selection; return useMutation({ mutationKey: customMutationKeys.register(), - mutationFn: (variables: RegisterMutationVariables) => execute(registerMutationDocument, variables), - ...options + mutationFn: (variables: RegisterVariables) => getClient().mutation.register(variables, { + select: args.select + }).unwrap(), + ...mutationOptions }); -}" +} +" `; exports[`Custom Mutation Hook Generators generateCustomMutationHook generates custom mutation hook without arguments 1`] = ` @@ -264,28 +294,41 @@ exports[`Custom Mutation Hook Generators generateCustomMutationHook generates cu */ import { useMutation } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { LogoutPayload } from "../schema-types"; +import type { UseMutationOptions, UseMutationResult } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; import { customMutationKeys } from "../mutation-keys"; -/** GraphQL mutation document */ -export const logoutMutationDocument = \` -mutation LogoutMutation { - logout { - success - } -} -\`; -export interface LogoutMutationResult { - logout: LogoutPayload; -} -export function useLogoutMutation(options?: Omit, 'mutationFn'>) { +import type { LogoutPayloadSelect, LogoutPayload } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { LogoutPayloadSelect } from "../../orm/input-types"; +export function useLogoutMutation(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; +}, Error, void>, "mutationFn">): UseMutationResult<{ + logout: InferSelectResult; +}, Error, void>; +export function useLogoutMutation(params: { + selection: SelectionConfig; +} & Omit, "mutationFn">) { + const args = buildSelectionArgs(params.selection); + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; + void _selection; return useMutation({ mutationKey: customMutationKeys.logout(), - mutationFn: () => execute(logoutMutationDocument), - ...options + mutationFn: () => getClient().mutation.logout({ + select: args.select + }).unwrap(), + ...mutationOptions }); -}" +} +" `; exports[`Custom Mutation Hook Generators generateCustomMutationHook generates custom mutation hook without centralized keys 1`] = ` @@ -296,30 +339,41 @@ exports[`Custom Mutation Hook Generators generateCustomMutationHook generates cu */ import { useMutation } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { LoginPayload } from "../schema-types"; -/** GraphQL mutation document */ -export const loginMutationDocument = \` -mutation LoginMutation($email: String!, $password: String!) { - login(email: $email, password: $password) { - token - } -} -\`; -export interface LoginMutationVariables { - email: string; - password: string; -} -export interface LoginMutationResult { - login: LoginPayload; -} -export function useLoginMutation(options?: Omit, 'mutationFn'>) { +import type { UseMutationOptions, UseMutationResult } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; +import type { LoginVariables } from "../../orm/mutation"; +import type { LoginPayloadSelect, LoginPayload } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { LoginVariables } from "../../orm/mutation"; +export type { LoginPayloadSelect } from "../../orm/input-types"; +export function useLoginMutation(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; +}, Error, LoginVariables>, "mutationFn">): UseMutationResult<{ + login: InferSelectResult; +}, Error, LoginVariables>; +export function useLoginMutation(params: { + selection: SelectionConfig; +} & Omit, "mutationFn">) { + const args = buildSelectionArgs(params.selection); + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; + void _selection; return useMutation({ - mutationFn: (variables: LoginMutationVariables) => execute(loginMutationDocument, variables), - ...options + mutationFn: (variables: LoginVariables) => getClient().mutation.login(variables, { + select: args.select + }).unwrap(), + ...mutationOptions }); -}" +} +" `; exports[`Custom Query Hook Generators generateCustomQueryHook generates custom query hook with arguments 1`] = ` @@ -330,24 +384,16 @@ exports[`Custom Query Hook Generators generateCustomQueryHook generates custom q */ import { useQuery } from "@tanstack/react-query"; -import type { UseQueryOptions, QueryClient } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { ExecuteOptions } from "../client"; -import type { User } from "../schema-types"; +import type { UseQueryOptions, UseQueryResult, QueryClient } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; import { customQueryKeys } from "../query-keys"; -/** GraphQL query document */ -export const searchUsersQueryDocument = \` -query SearchUsersQuery($query: String!, $limit: Int) { - searchUsers(query: $query, limit: $limit) -} -\`; -export interface SearchUsersQueryVariables { - query: string; - limit?: number; -} -export interface SearchUsersQueryResult { - searchUsers: User[]; -} +import type { SearchUsersVariables } from "../../orm/query"; +import type { UserSelect, User } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { SearchUsersVariables } from "../../orm/query"; +export type { UserSelect } from "../../orm/input-types"; /** Query key factory - re-exported from query-keys.ts */ export const searchUsersQueryKey = customQueryKeys.searchUsers; /** @@ -355,19 +401,43 @@ export const searchUsersQueryKey = customQueryKeys.searchUsers; * * @example * \`\`\`tsx - * const { data, isLoading } = useSearchUsersQuery({ query, limit }); + * const { data, isLoading } = useSearchUsersQuery({ variables: { query, limit }, selection: { fields: { id: true } } }); * * if (data?.searchUsers) { * console.log(data.searchUsers); * } * \`\`\` */ -export function useSearchUsersQuery(variables: SearchUsersQueryVariables, options?: Omit, 'queryKey' | 'queryFn'>) { +export function useSearchUsersQuery[]; +}>(params: { + variables: SearchUsersVariables; + selection: ({ + fields: S; + } & StrictSelect); +} & Omit[]; +}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; +export function useSearchUsersQuery(params: { + variables: SearchUsersVariables; + selection: SelectionConfig; +} & Omit, "queryKey" | "queryFn">) { + const variables = params.variables; + const args = buildSelectionArgs(params.selection); + const { + variables: _variables, + selection: _selection, + ...queryOptions + } = params ?? {}; + void _variables; + void _selection; return useQuery({ queryKey: searchUsersQueryKey(variables), - queryFn: () => execute(searchUsersQueryDocument, variables), - enabled: !!variables && options?.enabled !== false, - ...options + queryFn: () => getClient().query.searchUsers(variables!, { + select: args.select + }).unwrap(), + enabled: !!variables && params?.enabled !== false, + ...queryOptions }); } /** @@ -375,26 +445,55 @@ export function useSearchUsersQuery(variables: SearchUsersQueryVariables, option * * @example * \`\`\`ts - * const data = await fetchSearchUsersQuery({ query, limit }); + * const data = await fetchSearchUsersQuery({ variables: { query, limit }, selection: { fields: { id: true } } }); * \`\`\` */ -export async function fetchSearchUsersQuery(variables: SearchUsersQueryVariables, options?: ExecuteOptions): Promise { - return execute(searchUsersQueryDocument, variables, options); +export async function fetchSearchUsersQuery(params: { + variables: SearchUsersVariables; + selection: ({ + fields: S; + } & StrictSelect); +}): Promise<{ + searchUsers: InferSelectResult[]; +}>; +export async function fetchSearchUsersQuery(params: { + variables: SearchUsersVariables; + selection: SelectionConfig; +}) { + const variables = params.variables; + const args = buildSelectionArgs(params.selection); + return getClient().query.searchUsers(variables!, { + select: args.select + }).unwrap(); } /** * Prefetch searchUsers for SSR or cache warming * * @example * \`\`\`ts - * await prefetchSearchUsersQuery(queryClient, { query, limit }); + * await prefetchSearchUsersQuery(queryClient, { variables: { query, limit }, selection: { fields: { id: true } } }); * \`\`\` */ -export async function prefetchSearchUsersQuery(queryClient: QueryClient, variables: SearchUsersQueryVariables, options?: ExecuteOptions): Promise { +export async function prefetchSearchUsersQuery(queryClient: QueryClient, params: { + variables: SearchUsersVariables; + selection: ({ + fields: S; + } & StrictSelect); +}): Promise; +export async function prefetchSearchUsersQuery(queryClient: QueryClient, params: { + variables: SearchUsersVariables; + selection: SelectionConfig; +}): Promise { + const variables = params.variables; + const args = buildSelectionArgs(params.selection); await queryClient.prefetchQuery({ queryKey: searchUsersQueryKey(variables), - queryFn: () => execute(searchUsersQueryDocument, variables, options) + queryFn: () => getClient().query.searchUsers(variables!, { + select: args.select + }).unwrap() }); -}" +} +" `; exports[`Custom Query Hook Generators generateCustomQueryHook generates custom query hook without arguments 1`] = ` @@ -405,20 +504,14 @@ exports[`Custom Query Hook Generators generateCustomQueryHook generates custom q */ import { useQuery } from "@tanstack/react-query"; -import type { UseQueryOptions, QueryClient } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { ExecuteOptions } from "../client"; -import type { User } from "../schema-types"; +import type { UseQueryOptions, UseQueryResult, QueryClient } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; import { customQueryKeys } from "../query-keys"; -/** GraphQL query document */ -export const currentUserQueryDocument = \` -query CurrentUserQuery { - currentUser -} -\`; -export interface CurrentUserQueryResult { - currentUser: User; -} +import type { UserSelect, User } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { UserSelect } from "../../orm/input-types"; /** Query key factory - re-exported from query-keys.ts */ export const currentUserQueryKey = customQueryKeys.currentUser; /** @@ -426,18 +519,37 @@ export const currentUserQueryKey = customQueryKeys.currentUser; * * @example * \`\`\`tsx - * const { data, isLoading } = useCurrentUserQuery(); + * const { data, isLoading } = useCurrentUserQuery({ selection: { fields: { id: true } } }); * * if (data?.currentUser) { * console.log(data.currentUser); * } * \`\`\` */ -export function useCurrentUserQuery(options?: Omit, 'queryKey' | 'queryFn'>) { +export function useCurrentUserQuery; +}>(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; +}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; +export function useCurrentUserQuery(params: { + selection: SelectionConfig; +} & Omit, "queryKey" | "queryFn">) { + const args = buildSelectionArgs(params.selection); + const { + selection: _selection, + ...queryOptions + } = params ?? {}; + void _selection; return useQuery({ queryKey: currentUserQueryKey(), - queryFn: () => execute(currentUserQueryDocument), - ...options + queryFn: () => getClient().query.currentUser({ + select: args.select + }).unwrap(), + ...queryOptions }); } /** @@ -445,26 +557,49 @@ export function useCurrentUserQuery(options?: Omit { - return execute(currentUserQueryDocument, undefined, options); +export async function fetchCurrentUserQuery(params: { + selection: ({ + fields: S; + } & StrictSelect); +}): Promise<{ + currentUser: InferSelectResult; +}>; +export async function fetchCurrentUserQuery(params: { + selection: SelectionConfig; +}) { + const args = buildSelectionArgs(params.selection); + return getClient().query.currentUser({ + select: args.select + }).unwrap(); } /** * Prefetch currentUser for SSR or cache warming * * @example * \`\`\`ts - * await prefetchCurrentUserQuery(queryClient); + * await prefetchCurrentUserQuery(queryClient, { selection: { fields: { id: true } } }); * \`\`\` */ -export async function prefetchCurrentUserQuery(queryClient: QueryClient, options?: ExecuteOptions): Promise { +export async function prefetchCurrentUserQuery(queryClient: QueryClient, params: { + selection: ({ + fields: S; + } & StrictSelect); +}): Promise; +export async function prefetchCurrentUserQuery(queryClient: QueryClient, params: { + selection: SelectionConfig; +}): Promise { + const args = buildSelectionArgs(params.selection); await queryClient.prefetchQuery({ queryKey: currentUserQueryKey(), - queryFn: () => execute(currentUserQueryDocument, undefined, options) + queryFn: () => getClient().query.currentUser({ + select: args.select + }).unwrap() }); -}" +} +" `; exports[`Custom Query Hook Generators generateCustomQueryHook generates custom query hook without centralized keys 1`] = ` @@ -475,19 +610,13 @@ exports[`Custom Query Hook Generators generateCustomQueryHook generates custom q */ import { useQuery } from "@tanstack/react-query"; -import type { UseQueryOptions, QueryClient } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { ExecuteOptions } from "../client"; -import type { User } from "../schema-types"; -/** GraphQL query document */ -export const currentUserQueryDocument = \` -query CurrentUserQuery { - currentUser -} -\`; -export interface CurrentUserQueryResult { - currentUser: User; -} +import type { UseQueryOptions, UseQueryResult, QueryClient } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; +import type { UserSelect, User } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { UserSelect } from "../../orm/input-types"; /** Query key factory for caching */ export const currentUserQueryKey = () => ["currentUser"] as const; /** @@ -495,18 +624,37 @@ export const currentUserQueryKey = () => ["currentUser"] as const; * * @example * \`\`\`tsx - * const { data, isLoading } = useCurrentUserQuery(); + * const { data, isLoading } = useCurrentUserQuery({ selection: { fields: { id: true } } }); * * if (data?.currentUser) { * console.log(data.currentUser); * } * \`\`\` */ -export function useCurrentUserQuery(options?: Omit, 'queryKey' | 'queryFn'>) { +export function useCurrentUserQuery; +}>(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; +}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; +export function useCurrentUserQuery(params: { + selection: SelectionConfig; +} & Omit, "queryKey" | "queryFn">) { + const args = buildSelectionArgs(params.selection); + const { + selection: _selection, + ...queryOptions + } = params ?? {}; + void _selection; return useQuery({ queryKey: currentUserQueryKey(), - queryFn: () => execute(currentUserQueryDocument), - ...options + queryFn: () => getClient().query.currentUser({ + select: args.select + }).unwrap(), + ...queryOptions }); } /** @@ -514,26 +662,49 @@ export function useCurrentUserQuery(options?: Omit { - return execute(currentUserQueryDocument, undefined, options); +export async function fetchCurrentUserQuery(params: { + selection: ({ + fields: S; + } & StrictSelect); +}): Promise<{ + currentUser: InferSelectResult; +}>; +export async function fetchCurrentUserQuery(params: { + selection: SelectionConfig; +}) { + const args = buildSelectionArgs(params.selection); + return getClient().query.currentUser({ + select: args.select + }).unwrap(); } /** * Prefetch currentUser for SSR or cache warming * * @example * \`\`\`ts - * await prefetchCurrentUserQuery(queryClient); + * await prefetchCurrentUserQuery(queryClient, { selection: { fields: { id: true } } }); * \`\`\` */ -export async function prefetchCurrentUserQuery(queryClient: QueryClient, options?: ExecuteOptions): Promise { +export async function prefetchCurrentUserQuery(queryClient: QueryClient, params: { + selection: ({ + fields: S; + } & StrictSelect); +}): Promise; +export async function prefetchCurrentUserQuery(queryClient: QueryClient, params: { + selection: SelectionConfig; +}): Promise { + const args = buildSelectionArgs(params.selection); await queryClient.prefetchQuery({ queryKey: currentUserQueryKey(), - queryFn: () => execute(currentUserQueryDocument, undefined, options) + queryFn: () => getClient().query.currentUser({ + select: args.select + }).unwrap() }); -}" +} +" `; exports[`Mutation Hook Generators generateCreateMutationHook generates create mutation hook for simple table 1`] = ` @@ -544,68 +715,65 @@ exports[`Mutation Hook Generators generateCreateMutationHook generates create mu */ import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { User } from "../types"; +import type { UseMutationOptions, UseMutationResult } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; import { userKeys } from "../query-keys"; import { userMutationKeys } from "../mutation-keys"; -export type { User } from "../types"; -export const createUserMutationDocument = \` -mutation CreateUserMutation($input: CreateUserInput!) { - createUser(input: $input) { - user { - id - email - name - createdAt - } - } -} -\`; -/** Input type for creating a User */ -interface UserCreateInput { - email?: string | null; - name?: string | null; -} -export interface CreateUserMutationVariables { - input: { - user: UserCreateInput; - }; -} -export interface CreateUserMutationResult { - createUser: { - user: User; - }; -} +import type { UserSelect, UserWithRelations, CreateUserInput } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { UserSelect, UserWithRelations, CreateUserInput } from "../../orm/input-types"; /** * Mutation hook for creating a User * * @example * \`\`\`tsx - * const { mutate, isPending } = useCreateUserMutation(); - * - * mutate({ - * input: { - * user: { - * // ... fields - * }, - * }, + * const { mutate, isPending } = useCreateUserMutation({ + * selection: { fields: { id: true, name: true } }, * }); + * + * mutate({ name: 'New item' }); * \`\`\` */ -export function useCreateUserMutation(options?: Omit, 'mutationFn'>) { +export function useCreateUserMutation(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; + }; +}, Error, CreateUserInput["user"]>, "mutationFn">): UseMutationResult<{ + createUser: { + user: InferSelectResult; + }; +}, Error, CreateUserInput["user"]>; +export function useCreateUserMutation(params: { + selection: SelectionConfig; +} & Omit, "mutationFn">) { + const args = buildSelectionArgs(params.selection); + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; + void _selection; const queryClient = useQueryClient(); return useMutation({ mutationKey: userMutationKeys.create(), - mutationFn: (variables: CreateUserMutationVariables) => execute(createUserMutationDocument, variables), + mutationFn: (data: CreateUserInput["user"]) => getClient().user.create({ + data, + select: args.select + }).unwrap(), onSuccess: () => { queryClient.invalidateQueries({ queryKey: userKeys.lists() }); }, - ...options + ...mutationOptions }); -}" +} +" `; exports[`Mutation Hook Generators generateCreateMutationHook generates create mutation hook for table with relationships 1`] = ` @@ -616,73 +784,65 @@ exports[`Mutation Hook Generators generateCreateMutationHook generates create mu */ import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { Post } from "../types"; +import type { UseMutationOptions, UseMutationResult } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; import { postKeys } from "../query-keys"; -import type { PostScope } from "../query-keys"; import { postMutationKeys } from "../mutation-keys"; -export type { Post } from "../types"; -export const createPostMutationDocument = \` -mutation CreatePostMutation($input: CreatePostInput!) { - createPost(input: $input) { - post { - id - title - content - authorId - published - createdAt - } - } -} -\`; -/** Input type for creating a Post */ -interface PostCreateInput { - title?: string | null; - content?: string | null; - authorId?: string | null; - published?: boolean | null; -} -export interface CreatePostMutationVariables { - input: { - post: PostCreateInput; - }; -} -export interface CreatePostMutationResult { - createPost: { - post: Post; - }; -} +import type { PostSelect, PostWithRelations, CreatePostInput } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { PostSelect, PostWithRelations, CreatePostInput } from "../../orm/input-types"; /** * Mutation hook for creating a Post * * @example * \`\`\`tsx - * const { mutate, isPending } = useCreatePostMutation(); - * - * mutate({ - * input: { - * post: { - * // ... fields - * }, - * }, + * const { mutate, isPending } = useCreatePostMutation({ + * selection: { fields: { id: true, name: true } }, * }); + * + * mutate({ name: 'New item' }); * \`\`\` */ -export function useCreatePostMutation(options?: Omit, 'mutationFn'>) { +export function useCreatePostMutation(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; + }; +}, Error, CreatePostInput["post"]>, "mutationFn">): UseMutationResult<{ + createPost: { + post: InferSelectResult; + }; +}, Error, CreatePostInput["post"]>; +export function useCreatePostMutation(params: { + selection: SelectionConfig; +} & Omit, "mutationFn">) { + const args = buildSelectionArgs(params.selection); + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; + void _selection; const queryClient = useQueryClient(); return useMutation({ mutationKey: postMutationKeys.create(), - mutationFn: (variables: CreatePostMutationVariables) => execute(createPostMutationDocument, variables), + mutationFn: (data: CreatePostInput["post"]) => getClient().post.create({ + data, + select: args.select + }).unwrap(), onSuccess: () => { queryClient.invalidateQueries({ queryKey: postKeys.lists() }); }, - ...options + ...mutationOptions }); -}" +} +" `; exports[`Mutation Hook Generators generateCreateMutationHook generates create mutation hook without centralized keys 1`] = ` @@ -693,65 +853,62 @@ exports[`Mutation Hook Generators generateCreateMutationHook generates create mu */ import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { User } from "../types"; -export type { User } from "../types"; -export const createUserMutationDocument = \` -mutation CreateUserMutation($input: CreateUserInput!) { - createUser(input: $input) { - user { - id - email - name - createdAt - } - } -} -\`; -/** Input type for creating a User */ -interface UserCreateInput { - email?: string | null; - name?: string | null; -} -export interface CreateUserMutationVariables { - input: { - user: UserCreateInput; - }; -} -export interface CreateUserMutationResult { - createUser: { - user: User; - }; -} +import type { UseMutationOptions, UseMutationResult } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; +import type { UserSelect, UserWithRelations, CreateUserInput } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { UserSelect, UserWithRelations, CreateUserInput } from "../../orm/input-types"; /** * Mutation hook for creating a User * * @example * \`\`\`tsx - * const { mutate, isPending } = useCreateUserMutation(); - * - * mutate({ - * input: { - * user: { - * // ... fields - * }, - * }, + * const { mutate, isPending } = useCreateUserMutation({ + * selection: { fields: { id: true, name: true } }, * }); + * + * mutate({ name: 'New item' }); * \`\`\` */ -export function useCreateUserMutation(options?: Omit, 'mutationFn'>) { +export function useCreateUserMutation(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; + }; +}, Error, CreateUserInput["user"]>, "mutationFn">): UseMutationResult<{ + createUser: { + user: InferSelectResult; + }; +}, Error, CreateUserInput["user"]>; +export function useCreateUserMutation(params: { + selection: SelectionConfig; +} & Omit, "mutationFn">) { + const args = buildSelectionArgs(params.selection); + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; + void _selection; const queryClient = useQueryClient(); return useMutation({ - mutationFn: (variables: CreateUserMutationVariables) => execute(createUserMutationDocument, variables), + mutationFn: (data: CreateUserInput["user"]) => getClient().user.create({ + data, + select: args.select + }).unwrap(), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["user", "list"] }); }, - ...options + ...mutationOptions }); -}" +} +" `; exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mutation hook for simple table 1`] = ` @@ -762,57 +919,80 @@ exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mu */ import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; +import type { UseMutationOptions, UseMutationResult } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; import { userKeys } from "../query-keys"; import { userMutationKeys } from "../mutation-keys"; -export const deleteUserMutationDocument = \` -mutation DeleteUserMutation($input: DeleteUserInput!) { - deleteUser(input: $input) { - clientMutationId - } -} -\`; -export interface DeleteUserMutationVariables { - input: { - id: string; - }; -} -export interface DeleteUserMutationResult { - deleteUser: { - clientMutationId: string | null; - }; -} +import type { UserSelect, UserWithRelations } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { UserSelect, UserWithRelations } from "../../orm/input-types"; /** - * Mutation hook for deleting a User + * Mutation hook for deleting a User with typed selection * * @example * \`\`\`tsx - * const { mutate, isPending } = useDeleteUserMutation(); - * - * mutate({ - * input: { - * id: 'value-to-delete', - * }, + * const { mutate, isPending } = useDeleteUserMutation({ + * selection: { fields: { id: true } }, * }); + * + * mutate({ id: 'value-to-delete' }); * \`\`\` */ -export function useDeleteUserMutation(options?: Omit, 'mutationFn'>) { +export function useDeleteUserMutation(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; + }; +}, Error, { + id: string; +}>, "mutationFn">): UseMutationResult<{ + deleteUser: { + user: InferSelectResult; + }; +}, Error, { + id: string; +}>; +export function useDeleteUserMutation(params: { + selection: SelectionConfig; +} & Omit, "mutationFn">) { + const args = buildSelectionArgs(params.selection); + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; + void _selection; const queryClient = useQueryClient(); return useMutation({ mutationKey: userMutationKeys.all, - mutationFn: (variables: DeleteUserMutationVariables) => execute(deleteUserMutationDocument, variables), + mutationFn: ({ + id + }: { + id: string; + }) => getClient().user.delete({ + where: { + id + }, + select: args.select + }).unwrap(), onSuccess: (_, variables) => { queryClient.removeQueries({ - queryKey: userKeys.detail(variables.input.id) + queryKey: userKeys.detail(variables.id) }); queryClient.invalidateQueries({ queryKey: userKeys.lists() }); }, - ...options + ...mutationOptions }); -}" +} +" `; exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mutation hook for table with relationships 1`] = ` @@ -823,58 +1003,80 @@ exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mu */ import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; +import type { UseMutationOptions, UseMutationResult } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; import { postKeys } from "../query-keys"; -import type { PostScope } from "../query-keys"; import { postMutationKeys } from "../mutation-keys"; -export const deletePostMutationDocument = \` -mutation DeletePostMutation($input: DeletePostInput!) { - deletePost(input: $input) { - clientMutationId - } -} -\`; -export interface DeletePostMutationVariables { - input: { - id: string; - }; -} -export interface DeletePostMutationResult { - deletePost: { - clientMutationId: string | null; - }; -} +import type { PostSelect, PostWithRelations } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { PostSelect, PostWithRelations } from "../../orm/input-types"; /** - * Mutation hook for deleting a Post + * Mutation hook for deleting a Post with typed selection * * @example * \`\`\`tsx - * const { mutate, isPending } = useDeletePostMutation(); - * - * mutate({ - * input: { - * id: 'value-to-delete', - * }, + * const { mutate, isPending } = useDeletePostMutation({ + * selection: { fields: { id: true } }, * }); + * + * mutate({ id: 'value-to-delete' }); * \`\`\` */ -export function useDeletePostMutation(options?: Omit, 'mutationFn'>) { +export function useDeletePostMutation(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; + }; +}, Error, { + id: string; +}>, "mutationFn">): UseMutationResult<{ + deletePost: { + post: InferSelectResult; + }; +}, Error, { + id: string; +}>; +export function useDeletePostMutation(params: { + selection: SelectionConfig; +} & Omit, "mutationFn">) { + const args = buildSelectionArgs(params.selection); + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; + void _selection; const queryClient = useQueryClient(); return useMutation({ mutationKey: postMutationKeys.all, - mutationFn: (variables: DeletePostMutationVariables) => execute(deletePostMutationDocument, variables), + mutationFn: ({ + id + }: { + id: string; + }) => getClient().post.delete({ + where: { + id + }, + select: args.select + }).unwrap(), onSuccess: (_, variables) => { queryClient.removeQueries({ - queryKey: postKeys.detail(variables.input.id) + queryKey: postKeys.detail(variables.id) }); queryClient.invalidateQueries({ queryKey: postKeys.lists() }); }, - ...options + ...mutationOptions }); -}" +} +" `; exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mutation hook without centralized keys 1`] = ` @@ -885,54 +1087,77 @@ exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mu */ import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -export const deleteUserMutationDocument = \` -mutation DeleteUserMutation($input: DeleteUserInput!) { - deleteUser(input: $input) { - clientMutationId - } -} -\`; -export interface DeleteUserMutationVariables { - input: { - id: string; - }; -} -export interface DeleteUserMutationResult { - deleteUser: { - clientMutationId: string | null; - }; -} +import type { UseMutationOptions, UseMutationResult } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; +import type { UserSelect, UserWithRelations } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { UserSelect, UserWithRelations } from "../../orm/input-types"; /** - * Mutation hook for deleting a User + * Mutation hook for deleting a User with typed selection * * @example * \`\`\`tsx - * const { mutate, isPending } = useDeleteUserMutation(); - * - * mutate({ - * input: { - * id: 'value-to-delete', - * }, + * const { mutate, isPending } = useDeleteUserMutation({ + * selection: { fields: { id: true } }, * }); + * + * mutate({ id: 'value-to-delete' }); * \`\`\` */ -export function useDeleteUserMutation(options?: Omit, 'mutationFn'>) { +export function useDeleteUserMutation(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; + }; +}, Error, { + id: string; +}>, "mutationFn">): UseMutationResult<{ + deleteUser: { + user: InferSelectResult; + }; +}, Error, { + id: string; +}>; +export function useDeleteUserMutation(params: { + selection: SelectionConfig; +} & Omit, "mutationFn">) { + const args = buildSelectionArgs(params.selection); + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; + void _selection; const queryClient = useQueryClient(); return useMutation({ - mutationFn: (variables: DeleteUserMutationVariables) => execute(deleteUserMutationDocument, variables), + mutationFn: ({ + id + }: { + id: string; + }) => getClient().user.delete({ + where: { + id + }, + select: args.select + }).unwrap(), onSuccess: (_, variables) => { queryClient.removeQueries({ - queryKey: ["user", "detail", variables.input.id] + queryKey: ["user", "detail", variables.id] }); queryClient.invalidateQueries({ queryKey: ["user", "list"] }); }, - ...options + ...mutationOptions }); -}" +} +" `; exports[`Mutation Hook Generators generateUpdateMutationHook generates update mutation hook for simple table 1`] = ` @@ -943,74 +1168,86 @@ exports[`Mutation Hook Generators generateUpdateMutationHook generates update mu */ import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { User } from "../types"; +import type { UseMutationOptions, UseMutationResult } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; import { userKeys } from "../query-keys"; import { userMutationKeys } from "../mutation-keys"; -export type { User } from "../types"; -export const updateUserMutationDocument = \` -mutation UpdateUserMutation($input: UpdateUserInput!) { - updateUser(input: $input) { - user { - id - email - name - createdAt - } - } -} -\`; -/** Patch type for updating a User - all fields optional */ -interface UserPatch { - email?: string | null; - name?: string | null; - createdAt?: string | null; -} -export interface UpdateUserMutationVariables { - input: { - id: string; - patch: UserPatch; - }; -} -export interface UpdateUserMutationResult { - updateUser: { - user: User; - }; -} +import type { UserSelect, UserWithRelations, UserPatch } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { UserSelect, UserWithRelations, UserPatch } from "../../orm/input-types"; /** * Mutation hook for updating a User * * @example * \`\`\`tsx - * const { mutate, isPending } = useUpdateUserMutation(); - * - * mutate({ - * input: { - * id: 'value-here', - * patch: { - * // ... fields to update - * }, - * }, + * const { mutate, isPending } = useUpdateUserMutation({ + * selection: { fields: { id: true, name: true } }, * }); + * + * mutate({ id: 'value-here', patch: { name: 'Updated' } }); * \`\`\` */ -export function useUpdateUserMutation(options?: Omit, 'mutationFn'>) { +export function useUpdateUserMutation(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; + }; +}, Error, { + id: string; + patch: UserPatch; +}>, "mutationFn">): UseMutationResult<{ + updateUser: { + user: InferSelectResult; + }; +}, Error, { + id: string; + patch: UserPatch; +}>; +export function useUpdateUserMutation(params: { + selection: SelectionConfig; +} & Omit, "mutationFn">) { + const args = buildSelectionArgs(params.selection); + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; + void _selection; const queryClient = useQueryClient(); return useMutation({ mutationKey: userMutationKeys.all, - mutationFn: (variables: UpdateUserMutationVariables) => execute(updateUserMutationDocument, variables), + mutationFn: ({ + id, + patch + }: { + id: string; + patch: UserPatch; + }) => getClient().user.update({ + where: { + id + }, + data: patch, + select: args.select + }).unwrap(), onSuccess: (_, variables) => { queryClient.invalidateQueries({ - queryKey: userKeys.detail(variables.input.id) + queryKey: userKeys.detail(variables.id) }); queryClient.invalidateQueries({ queryKey: userKeys.lists() }); }, - ...options + ...mutationOptions }); -}" +} +" `; exports[`Mutation Hook Generators generateUpdateMutationHook generates update mutation hook for table with relationships 1`] = ` @@ -1021,79 +1258,86 @@ exports[`Mutation Hook Generators generateUpdateMutationHook generates update mu */ import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { Post } from "../types"; +import type { UseMutationOptions, UseMutationResult } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; import { postKeys } from "../query-keys"; -import type { PostScope } from "../query-keys"; import { postMutationKeys } from "../mutation-keys"; -export type { Post } from "../types"; -export const updatePostMutationDocument = \` -mutation UpdatePostMutation($input: UpdatePostInput!) { - updatePost(input: $input) { - post { - id - title - content - authorId - published - createdAt - } - } -} -\`; -/** Patch type for updating a Post - all fields optional */ -interface PostPatch { - title?: string | null; - content?: string | null; - authorId?: string | null; - published?: boolean | null; - createdAt?: string | null; -} -export interface UpdatePostMutationVariables { - input: { - id: string; - patch: PostPatch; - }; -} -export interface UpdatePostMutationResult { - updatePost: { - post: Post; - }; -} +import type { PostSelect, PostWithRelations, PostPatch } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { PostSelect, PostWithRelations, PostPatch } from "../../orm/input-types"; /** * Mutation hook for updating a Post * * @example * \`\`\`tsx - * const { mutate, isPending } = useUpdatePostMutation(); - * - * mutate({ - * input: { - * id: 'value-here', - * patch: { - * // ... fields to update - * }, - * }, + * const { mutate, isPending } = useUpdatePostMutation({ + * selection: { fields: { id: true, name: true } }, * }); + * + * mutate({ id: 'value-here', patch: { name: 'Updated' } }); * \`\`\` */ -export function useUpdatePostMutation(options?: Omit, 'mutationFn'>) { +export function useUpdatePostMutation(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; + }; +}, Error, { + id: string; + patch: PostPatch; +}>, "mutationFn">): UseMutationResult<{ + updatePost: { + post: InferSelectResult; + }; +}, Error, { + id: string; + patch: PostPatch; +}>; +export function useUpdatePostMutation(params: { + selection: SelectionConfig; +} & Omit, "mutationFn">) { + const args = buildSelectionArgs(params.selection); + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; + void _selection; const queryClient = useQueryClient(); return useMutation({ mutationKey: postMutationKeys.all, - mutationFn: (variables: UpdatePostMutationVariables) => execute(updatePostMutationDocument, variables), + mutationFn: ({ + id, + patch + }: { + id: string; + patch: PostPatch; + }) => getClient().post.update({ + where: { + id + }, + data: patch, + select: args.select + }).unwrap(), onSuccess: (_, variables) => { queryClient.invalidateQueries({ - queryKey: postKeys.detail(variables.input.id) + queryKey: postKeys.detail(variables.id) }); queryClient.invalidateQueries({ queryKey: postKeys.lists() }); }, - ...options + ...mutationOptions }); -}" +} +" `; exports[`Mutation Hook Generators generateUpdateMutationHook generates update mutation hook without centralized keys 1`] = ` @@ -1104,71 +1348,83 @@ exports[`Mutation Hook Generators generateUpdateMutationHook generates update mu */ import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { User } from "../types"; -export type { User } from "../types"; -export const updateUserMutationDocument = \` -mutation UpdateUserMutation($input: UpdateUserInput!) { - updateUser(input: $input) { - user { - id - email - name - createdAt - } - } -} -\`; -/** Patch type for updating a User - all fields optional */ -interface UserPatch { - email?: string | null; - name?: string | null; - createdAt?: string | null; -} -export interface UpdateUserMutationVariables { - input: { - id: string; - patch: UserPatch; - }; -} -export interface UpdateUserMutationResult { - updateUser: { - user: User; - }; -} +import type { UseMutationOptions, UseMutationResult } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; +import type { UserSelect, UserWithRelations, UserPatch } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { UserSelect, UserWithRelations, UserPatch } from "../../orm/input-types"; /** * Mutation hook for updating a User * * @example * \`\`\`tsx - * const { mutate, isPending } = useUpdateUserMutation(); - * - * mutate({ - * input: { - * id: 'value-here', - * patch: { - * // ... fields to update - * }, - * }, + * const { mutate, isPending } = useUpdateUserMutation({ + * selection: { fields: { id: true, name: true } }, * }); + * + * mutate({ id: 'value-here', patch: { name: 'Updated' } }); * \`\`\` */ -export function useUpdateUserMutation(options?: Omit, 'mutationFn'>) { +export function useUpdateUserMutation(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; + }; +}, Error, { + id: string; + patch: UserPatch; +}>, "mutationFn">): UseMutationResult<{ + updateUser: { + user: InferSelectResult; + }; +}, Error, { + id: string; + patch: UserPatch; +}>; +export function useUpdateUserMutation(params: { + selection: SelectionConfig; +} & Omit, "mutationFn">) { + const args = buildSelectionArgs(params.selection); + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; + void _selection; const queryClient = useQueryClient(); return useMutation({ - mutationFn: (variables: UpdateUserMutationVariables) => execute(updateUserMutationDocument, variables), + mutationFn: ({ + id, + patch + }: { + id: string; + patch: UserPatch; + }) => getClient().user.update({ + where: { + id + }, + data: patch, + select: args.select + }).unwrap(), onSuccess: (_, variables) => { queryClient.invalidateQueries({ - queryKey: ["user", "detail", variables.input.id] + queryKey: ["user", "detail", variables.id] }); queryClient.invalidateQueries({ queryKey: ["user", "list"] }); }, - ...options + ...mutationOptions }); -}" +} +" `; exports[`Query Hook Generators generateListQueryHook generates list query hook for simple table 1`] = ` @@ -1179,78 +1435,14 @@ exports[`Query Hook Generators generateListQueryHook generates list query hook f */ import { useQuery } from "@tanstack/react-query"; -import type { UseQueryOptions, QueryClient } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { ExecuteOptions } from "../client"; -import type { User, UUIDFilter, StringFilter, DatetimeFilter } from "../types"; +import type { UseQueryOptions, UseQueryResult, QueryClient } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildListSelectionArgs } from "../selection"; +import type { ListSelectionConfig } from "../selection"; import { userKeys } from "../query-keys"; -export type { User } from "../types"; -export const usersQueryDocument = \` -query UsersQuery($first: Int, $last: Int, $offset: Int, $before: Cursor, $after: Cursor, $filter: UserFilter, $condition: UserCondition, $orderBy: [UsersOrderBy!]) { - users( - first: $first - last: $last - offset: $offset - before: $before - after: $after - filter: $filter - condition: $condition - orderBy: $orderBy - ) { - totalCount - nodes { - id - email - name - createdAt - } - pageInfo { - hasNextPage - hasPreviousPage - startCursor - endCursor - } - } -} -\`; -interface UserFilter { - id?: UUIDFilter; - email?: StringFilter; - name?: StringFilter; - createdAt?: DatetimeFilter; - and?: UserFilter[]; - or?: UserFilter[]; - not?: UserFilter; -} -interface UserCondition { - id?: string; - email?: string; - name?: string; - createdAt?: string; -} -type UsersOrderBy = "ID_ASC" | "ID_DESC" | "EMAIL_ASC" | "EMAIL_DESC" | "NAME_ASC" | "NAME_DESC" | "CREATED_AT_ASC" | "CREATED_AT_DESC" | "NATURAL" | "PRIMARY_KEY_ASC" | "PRIMARY_KEY_DESC"; -export interface UsersQueryVariables { - first?: number; - last?: number; - offset?: number; - before?: string; - after?: string; - filter?: UserFilter; - condition?: UserCondition; - orderBy?: UsersOrderBy[]; -} -export interface UsersQueryResult { - users: { - totalCount: number; - nodes: User[]; - pageInfo: { - hasNextPage: boolean; - hasPreviousPage: boolean; - startCursor: string | null; - endCursor: string | null; - }; - }; -} +import type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy } from "../../orm/input-types"; +import type { FindManyArgs, InferSelectResult, ConnectionResult, StrictSelect } from "../../orm/select-types"; +export type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy } from "../../orm/input-types"; /** Query key factory - re-exported from query-keys.ts */ export const usersQueryKey = userKeys.list; /** @@ -1259,17 +1451,37 @@ export const usersQueryKey = userKeys.list; * @example * \`\`\`tsx * const { data, isLoading } = useUsersQuery({ - * first: 10, - * filter: { name: { equalTo: "example" } }, - * orderBy: ['CREATED_AT_DESC'], + * selection: { + * fields: { id: true, name: true }, + * where: { name: { equalTo: "example" } }, + * orderBy: ['CREATED_AT_DESC'], + * first: 10, + * }, * }); * \`\`\` */ -export function useUsersQuery(variables?: UsersQueryVariables, options?: Omit, 'queryKey' | 'queryFn'>) { +export function useUsersQuery>; +}>(params: { + selection: { + fields: S; + } & Omit, "fields"> & StrictSelect; +} & Omit>; +}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; +export function useUsersQuery(params: { + selection: ListSelectionConfig; +} & Omit, "queryKey" | "queryFn">) { + const args = buildListSelectionArgs(params.selection); + const { + selection: _selection, + ...queryOptions + } = params ?? {}; + void _selection; return useQuery({ - queryKey: userKeys.list(variables), - queryFn: () => execute(usersQueryDocument, variables), - ...options + queryKey: userKeys.list(args), + queryFn: () => getClient().user.findMany(args).unwrap(), + ...queryOptions }); } /** @@ -1277,33 +1489,50 @@ export function useUsersQuery(variables?: UsersQueryVariables, options?: Omit fetchUsersQuery(variables), + * const data = await fetchUsersQuery({ + * selection: { + * fields: { id: true }, + * first: 10, + * }, * }); * \`\`\` */ -export async function fetchUsersQuery(variables?: UsersQueryVariables, options?: ExecuteOptions): Promise { - return execute(usersQueryDocument, variables, options); +export async function fetchUsersQuery(params: { + selection: { + fields: S; + } & Omit, "fields"> & StrictSelect; +}): Promise<{ + users: ConnectionResult>; +}>; +export async function fetchUsersQuery(params: { + selection: ListSelectionConfig; +}) { + const args = buildListSelectionArgs(params.selection); + return getClient().user.findMany(args).unwrap(); } /** * Prefetch User list for SSR or cache warming * * @example * \`\`\`ts - * await prefetchUsersQuery(queryClient, { first: 10 }); + * await prefetchUsersQuery(queryClient, { selection: { fields: { id: true }, first: 10 } }); * \`\`\` */ -export async function prefetchUsersQuery(queryClient: QueryClient, variables?: UsersQueryVariables, options?: ExecuteOptions): Promise { +export async function prefetchUsersQuery(queryClient: QueryClient, params: { + selection: { + fields: S; + } & Omit, "fields"> & StrictSelect; +}): Promise; +export async function prefetchUsersQuery(queryClient: QueryClient, params: { + selection: ListSelectionConfig; +}): Promise { + const args = buildListSelectionArgs(params.selection); await queryClient.prefetchQuery({ - queryKey: userKeys.list(variables), - queryFn: () => execute(usersQueryDocument, variables, options) + queryKey: userKeys.list(args), + queryFn: () => getClient().user.findMany(args).unwrap() }); -}" +} +" `; exports[`Query Hook Generators generateListQueryHook generates list query hook for table with relationships 1`] = ` @@ -1314,85 +1543,15 @@ exports[`Query Hook Generators generateListQueryHook generates list query hook f */ import { useQuery } from "@tanstack/react-query"; -import type { UseQueryOptions, QueryClient } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { ExecuteOptions } from "../client"; -import type { Post, UUIDFilter, StringFilter, BooleanFilter, DatetimeFilter } from "../types"; +import type { UseQueryOptions, UseQueryResult, QueryClient } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildListSelectionArgs } from "../selection"; +import type { ListSelectionConfig } from "../selection"; import { postKeys } from "../query-keys"; import type { PostScope } from "../query-keys"; -export type { Post } from "../types"; -export const postsQueryDocument = \` -query PostsQuery($first: Int, $last: Int, $offset: Int, $before: Cursor, $after: Cursor, $filter: PostFilter, $condition: PostCondition, $orderBy: [PostsOrderBy!]) { - posts( - first: $first - last: $last - offset: $offset - before: $before - after: $after - filter: $filter - condition: $condition - orderBy: $orderBy - ) { - totalCount - nodes { - id - title - content - authorId - published - createdAt - } - pageInfo { - hasNextPage - hasPreviousPage - startCursor - endCursor - } - } -} -\`; -interface PostFilter { - id?: UUIDFilter; - title?: StringFilter; - content?: StringFilter; - authorId?: UUIDFilter; - published?: BooleanFilter; - createdAt?: DatetimeFilter; - and?: PostFilter[]; - or?: PostFilter[]; - not?: PostFilter; -} -interface PostCondition { - id?: string; - title?: string; - content?: string; - authorId?: string; - published?: boolean; - createdAt?: string; -} -type PostsOrderBy = "ID_ASC" | "ID_DESC" | "TITLE_ASC" | "TITLE_DESC" | "CONTENT_ASC" | "CONTENT_DESC" | "AUTHOR_ID_ASC" | "AUTHOR_ID_DESC" | "PUBLISHED_ASC" | "PUBLISHED_DESC" | "CREATED_AT_ASC" | "CREATED_AT_DESC" | "NATURAL" | "PRIMARY_KEY_ASC" | "PRIMARY_KEY_DESC"; -export interface PostsQueryVariables { - first?: number; - last?: number; - offset?: number; - before?: string; - after?: string; - filter?: PostFilter; - condition?: PostCondition; - orderBy?: PostsOrderBy[]; -} -export interface PostsQueryResult { - posts: { - totalCount: number; - nodes: Post[]; - pageInfo: { - hasNextPage: boolean; - hasPreviousPage: boolean; - startCursor: string | null; - endCursor: string | null; - }; - }; -} +import type { PostSelect, PostWithRelations, PostFilter, PostsOrderBy } from "../../orm/input-types"; +import type { FindManyArgs, InferSelectResult, ConnectionResult, StrictSelect } from "../../orm/select-types"; +export type { PostSelect, PostWithRelations, PostFilter, PostsOrderBy } from "../../orm/input-types"; /** Query key factory - re-exported from query-keys.ts */ export const postsQueryKey = postKeys.list; /** @@ -1401,28 +1560,49 @@ export const postsQueryKey = postKeys.list; * @example * \`\`\`tsx * const { data, isLoading } = usePostsQuery({ - * first: 10, - * filter: { name: { equalTo: "example" } }, - * orderBy: ['CREATED_AT_DESC'], + * selection: { + * fields: { id: true, name: true }, + * where: { name: { equalTo: "example" } }, + * orderBy: ['CREATED_AT_DESC'], + * first: 10, + * }, * }); * \`\`\` * * @example With scope for hierarchical cache invalidation * \`\`\`tsx - * const { data } = usePostsQuery( - * { first: 10 }, - * { scope: { parentId: 'parent-id' } } - * ); + * const { data } = usePostsQuery({ + * selection: { fields: { id: true }, first: 10 }, + * scope: { parentId: 'parent-id' }, + * }); * \`\`\` */ -export function usePostsQuery(variables?: PostsQueryVariables, options?: Omit, 'queryKey' | 'queryFn'> & { scope?: PostScope }) { +export function usePostsQuery>; +}>(params: { + selection: { + fields: S; + } & Omit, "fields"> & StrictSelect; +} & Omit>; +}, Error, TData>, "queryKey" | "queryFn"> & { + scope?: PostScope; +}): UseQueryResult; +export function usePostsQuery(params: { + selection: ListSelectionConfig; +} & Omit, "queryKey" | "queryFn"> & { + scope?: PostScope; +}) { + const args = buildListSelectionArgs(params.selection); const { scope, + selection: _selection, ...queryOptions - } = options ?? {}; + } = params ?? {}; + void _selection; return useQuery({ - queryKey: postKeys.list(variables, scope), - queryFn: () => execute(postsQueryDocument, variables), + queryKey: postKeys.list(args, scope), + queryFn: () => getClient().post.findMany(args).unwrap(), ...queryOptions }); } @@ -1431,33 +1611,54 @@ export function usePostsQuery(variables?: PostsQueryVariables, options?: Omit fetchPostsQuery(variables), + * const data = await fetchPostsQuery({ + * selection: { + * fields: { id: true }, + * first: 10, + * }, * }); * \`\`\` */ -export async function fetchPostsQuery(variables?: PostsQueryVariables, options?: ExecuteOptions): Promise { - return execute(postsQueryDocument, variables, options); +export async function fetchPostsQuery(params: { + selection: { + fields: S; + } & Omit, "fields"> & StrictSelect; +}): Promise<{ + posts: ConnectionResult>; +}>; +export async function fetchPostsQuery(params: { + selection: ListSelectionConfig; +}) { + const args = buildListSelectionArgs(params.selection); + return getClient().post.findMany(args).unwrap(); } /** * Prefetch Post list for SSR or cache warming * * @example * \`\`\`ts - * await prefetchPostsQuery(queryClient, { first: 10 }); + * await prefetchPostsQuery(queryClient, { selection: { fields: { id: true }, first: 10 } }); * \`\`\` */ -export async function prefetchPostsQuery(queryClient: QueryClient, variables?: PostsQueryVariables, scope?: PostScope, options?: ExecuteOptions): Promise { +export async function prefetchPostsQuery(queryClient: QueryClient, params: { + selection: { + fields: S; + } & Omit, "fields"> & StrictSelect; +} & { + scope?: PostScope; +}): Promise; +export async function prefetchPostsQuery(queryClient: QueryClient, params: { + selection: ListSelectionConfig; +} & { + scope?: PostScope; +}): Promise { + const args = buildListSelectionArgs(params.selection); await queryClient.prefetchQuery({ - queryKey: postKeys.list(variables, scope), - queryFn: () => execute(postsQueryDocument, variables, options) + queryKey: postKeys.list(args, params?.scope), + queryFn: () => getClient().post.findMany(args).unwrap() }); -}" +} +" `; exports[`Query Hook Generators generateListQueryHook generates list query hook without centralized keys 1`] = ` @@ -1468,95 +1669,51 @@ exports[`Query Hook Generators generateListQueryHook generates list query hook w */ import { useQuery } from "@tanstack/react-query"; -import type { UseQueryOptions, QueryClient } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { ExecuteOptions } from "../client"; -import type { User, UUIDFilter, StringFilter, DatetimeFilter } from "../types"; -export type { User } from "../types"; -export const usersQueryDocument = \` -query UsersQuery($first: Int, $last: Int, $offset: Int, $before: Cursor, $after: Cursor, $filter: UserFilter, $condition: UserCondition, $orderBy: [UsersOrderBy!]) { - users( - first: $first - last: $last - offset: $offset - before: $before - after: $after - filter: $filter - condition: $condition - orderBy: $orderBy - ) { - totalCount - nodes { - id - email - name - createdAt - } - pageInfo { - hasNextPage - hasPreviousPage - startCursor - endCursor - } - } -} -\`; -interface UserFilter { - id?: UUIDFilter; - email?: StringFilter; - name?: StringFilter; - createdAt?: DatetimeFilter; - and?: UserFilter[]; - or?: UserFilter[]; - not?: UserFilter; -} -interface UserCondition { - id?: string; - email?: string; - name?: string; - createdAt?: string; -} -type UsersOrderBy = "ID_ASC" | "ID_DESC" | "EMAIL_ASC" | "EMAIL_DESC" | "NAME_ASC" | "NAME_DESC" | "CREATED_AT_ASC" | "CREATED_AT_DESC" | "NATURAL" | "PRIMARY_KEY_ASC" | "PRIMARY_KEY_DESC"; -export interface UsersQueryVariables { - first?: number; - last?: number; - offset?: number; - before?: string; - after?: string; - filter?: UserFilter; - condition?: UserCondition; - orderBy?: UsersOrderBy[]; -} -export interface UsersQueryResult { - users: { - totalCount: number; - nodes: User[]; - pageInfo: { - hasNextPage: boolean; - hasPreviousPage: boolean; - startCursor: string | null; - endCursor: string | null; - }; - }; -} -export const usersQueryKey = (variables?: UsersQueryVariables) => ["user", "list", variables] as const; +import type { UseQueryOptions, UseQueryResult, QueryClient } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildListSelectionArgs } from "../selection"; +import type { ListSelectionConfig } from "../selection"; +import type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy } from "../../orm/input-types"; +import type { FindManyArgs, InferSelectResult, ConnectionResult, StrictSelect } from "../../orm/select-types"; +export type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy } from "../../orm/input-types"; +export const usersQueryKey = (variables?: FindManyArgs) => ["user", "list", variables] as const; /** * Query hook for fetching User list * * @example * \`\`\`tsx * const { data, isLoading } = useUsersQuery({ - * first: 10, - * filter: { name: { equalTo: "example" } }, - * orderBy: ['CREATED_AT_DESC'], + * selection: { + * fields: { id: true, name: true }, + * where: { name: { equalTo: "example" } }, + * orderBy: ['CREATED_AT_DESC'], + * first: 10, + * }, * }); * \`\`\` */ -export function useUsersQuery(variables?: UsersQueryVariables, options?: Omit, 'queryKey' | 'queryFn'>) { +export function useUsersQuery>; +}>(params: { + selection: { + fields: S; + } & Omit, "fields"> & StrictSelect; +} & Omit>; +}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; +export function useUsersQuery(params: { + selection: ListSelectionConfig; +} & Omit, "queryKey" | "queryFn">) { + const args = buildListSelectionArgs(params.selection); + const { + selection: _selection, + ...queryOptions + } = params ?? {}; + void _selection; return useQuery({ - queryKey: usersQueryKey(variables), - queryFn: () => execute(usersQueryDocument, variables), - ...options + queryKey: usersQueryKey(args), + queryFn: () => getClient().user.findMany(args).unwrap(), + ...queryOptions }); } /** @@ -1564,33 +1721,50 @@ export function useUsersQuery(variables?: UsersQueryVariables, options?: Omit fetchUsersQuery(variables), + * const data = await fetchUsersQuery({ + * selection: { + * fields: { id: true }, + * first: 10, + * }, * }); * \`\`\` */ -export async function fetchUsersQuery(variables?: UsersQueryVariables, options?: ExecuteOptions): Promise { - return execute(usersQueryDocument, variables, options); +export async function fetchUsersQuery(params: { + selection: { + fields: S; + } & Omit, "fields"> & StrictSelect; +}): Promise<{ + users: ConnectionResult>; +}>; +export async function fetchUsersQuery(params: { + selection: ListSelectionConfig; +}) { + const args = buildListSelectionArgs(params.selection); + return getClient().user.findMany(args).unwrap(); } /** * Prefetch User list for SSR or cache warming * * @example * \`\`\`ts - * await prefetchUsersQuery(queryClient, { first: 10 }); + * await prefetchUsersQuery(queryClient, { selection: { fields: { id: true }, first: 10 } }); * \`\`\` */ -export async function prefetchUsersQuery(queryClient: QueryClient, variables?: UsersQueryVariables, options?: ExecuteOptions): Promise { +export async function prefetchUsersQuery(queryClient: QueryClient, params: { + selection: { + fields: S; + } & Omit, "fields"> & StrictSelect; +}): Promise; +export async function prefetchUsersQuery(queryClient: QueryClient, params: { + selection: ListSelectionConfig; +}): Promise { + const args = buildListSelectionArgs(params.selection); await queryClient.prefetchQuery({ - queryKey: usersQueryKey(variables), - queryFn: () => execute(usersQueryDocument, variables, options) + queryKey: usersQueryKey(args), + queryFn: () => getClient().user.findMany(args).unwrap() }); -}" +} +" `; exports[`Query Hook Generators generateSingleQueryHook generates single query hook for simple table 1`] = ` @@ -1601,28 +1775,14 @@ exports[`Query Hook Generators generateSingleQueryHook generates single query ho */ import { useQuery } from "@tanstack/react-query"; -import type { UseQueryOptions, QueryClient } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { ExecuteOptions } from "../client"; -import type { User } from "../types"; +import type { UseQueryOptions, UseQueryResult, QueryClient } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; import { userKeys } from "../query-keys"; -export type { User } from "../types"; -export const userQueryDocument = \` -query UserQuery($id: UUID!) { - user(id: $id) { - id - email - name - createdAt - } -} -\`; -export interface UserQueryVariables { - id: string; -} -export interface UserQueryResult { - user: User | null; -} +import type { UserSelect, UserWithRelations } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { UserSelect, UserWithRelations } from "../../orm/input-types"; /** Query key factory - re-exported from query-keys.ts */ export const userQueryKey = userKeys.detail; /** @@ -1630,14 +1790,39 @@ export const userQueryKey = userKeys.detail; * * @example * \`\`\`tsx - * const { data, isLoading } = useUserQuery({ id: 'some-id' }); + * const { data, isLoading } = useUserQuery({ + * id: 'some-id', + * selection: { fields: { id: true, name: true } }, + * }); * \`\`\` */ -export function useUserQuery(variables: UserQueryVariables, options?: Omit, 'queryKey' | 'queryFn'>) { +export function useUserQuery | null; +}>(params: { + id: string; + selection: { + fields: S; + } & StrictSelect; +} & Omit | null; +}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; +export function useUserQuery(params: { + id: string; + selection: SelectionConfig; +} & Omit, "queryKey" | "queryFn">) { + const args = buildSelectionArgs(params.selection); + const { + selection: _selection, + ...queryOptions + } = params ?? {}; + void _selection; return useQuery({ - queryKey: userKeys.detail(variables.id), - queryFn: () => execute(userQueryDocument, variables), - ...options + queryKey: userKeys.detail(params.id), + queryFn: () => getClient().user.findOne({ + id: params.id, + select: args.select + }).unwrap(), + ...queryOptions }); } /** @@ -1645,26 +1830,58 @@ export function useUserQuery(variables: UserQueryVariables, options?: Omit { - return execute(userQueryDocument, variables, options); +export async function fetchUserQuery(params: { + id: string; + selection: { + fields: S; + } & StrictSelect; +}): Promise<{ + user: InferSelectResult | null; +}>; +export async function fetchUserQuery(params: { + id: string; + selection: SelectionConfig; +}) { + const args = buildSelectionArgs(params.selection); + return getClient().user.findOne({ + id: params.id, + select: args.select + }).unwrap(); } /** * Prefetch a single User for SSR or cache warming * * @example * \`\`\`ts - * await prefetchUserQuery(queryClient, { id: 'some-id' }); + * await prefetchUserQuery(queryClient, { id: 'some-id', selection: { fields: { id: true } } }); * \`\`\` */ -export async function prefetchUserQuery(queryClient: QueryClient, variables: UserQueryVariables, options?: ExecuteOptions): Promise { +export async function prefetchUserQuery(queryClient: QueryClient, params: { + id: string; + selection: { + fields: S; + } & StrictSelect; +}): Promise; +export async function prefetchUserQuery(queryClient: QueryClient, params: { + id: string; + selection: SelectionConfig; +}): Promise { + const args = buildSelectionArgs(params.selection); await queryClient.prefetchQuery({ - queryKey: userKeys.detail(variables.id), - queryFn: () => execute(userQueryDocument, variables, options) + queryKey: userKeys.detail(params.id), + queryFn: () => getClient().user.findOne({ + id: params.id, + select: args.select + }).unwrap() }); -}" +} +" `; exports[`Query Hook Generators generateSingleQueryHook generates single query hook for table with relationships 1`] = ` @@ -1675,31 +1892,15 @@ exports[`Query Hook Generators generateSingleQueryHook generates single query ho */ import { useQuery } from "@tanstack/react-query"; -import type { UseQueryOptions, QueryClient } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { ExecuteOptions } from "../client"; -import type { Post } from "../types"; +import type { UseQueryOptions, UseQueryResult, QueryClient } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; import { postKeys } from "../query-keys"; import type { PostScope } from "../query-keys"; -export type { Post } from "../types"; -export const postQueryDocument = \` -query PostQuery($id: UUID!) { - post(id: $id) { - id - title - content - authorId - published - createdAt - } -} -\`; -export interface PostQueryVariables { - id: string; -} -export interface PostQueryResult { - post: Post | null; -} +import type { PostSelect, PostWithRelations } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { PostSelect, PostWithRelations } from "../../orm/input-types"; /** Query key factory - re-exported from query-keys.ts */ export const postQueryKey = postKeys.detail; /** @@ -1707,25 +1908,52 @@ export const postQueryKey = postKeys.detail; * * @example * \`\`\`tsx - * const { data, isLoading } = usePostQuery({ id: 'some-id' }); + * const { data, isLoading } = usePostQuery({ + * id: 'some-id', + * selection: { fields: { id: true, name: true } }, + * }); * \`\`\` * * @example With scope for hierarchical cache invalidation * \`\`\`tsx - * const { data } = usePostQuery( - * { id: 'some-id' }, - * { scope: { parentId: 'parent-id' } } - * ); + * const { data } = usePostQuery({ + * id: 'some-id', + * selection: { fields: { id: true } }, + * scope: { parentId: 'parent-id' }, + * }); * \`\`\` */ -export function usePostQuery(variables: PostQueryVariables, options?: Omit, 'queryKey' | 'queryFn'> & { scope?: PostScope }) { +export function usePostQuery | null; +}>(params: { + id: string; + selection: { + fields: S; + } & StrictSelect; +} & Omit | null; +}, Error, TData>, "queryKey" | "queryFn"> & { + scope?: PostScope; +}): UseQueryResult; +export function usePostQuery(params: { + id: string; + selection: SelectionConfig; +} & Omit, "queryKey" | "queryFn"> & { + scope?: PostScope; +}) { + const args = buildSelectionArgs(params.selection); const { scope, + selection: _selection, ...queryOptions - } = options ?? {}; + } = params ?? {}; + void _selection; return useQuery({ - queryKey: postKeys.detail(variables.id, scope), - queryFn: () => execute(postQueryDocument, variables), + queryKey: postKeys.detail(params.id, scope), + queryFn: () => getClient().post.findOne({ + id: params.id, + select: args.select + }).unwrap(), ...queryOptions }); } @@ -1734,26 +1962,62 @@ export function usePostQuery(variables: PostQueryVariables, options?: Omit { - return execute(postQueryDocument, variables, options); +export async function fetchPostQuery(params: { + id: string; + selection: { + fields: S; + } & StrictSelect; +}): Promise<{ + post: InferSelectResult | null; +}>; +export async function fetchPostQuery(params: { + id: string; + selection: SelectionConfig; +}) { + const args = buildSelectionArgs(params.selection); + return getClient().post.findOne({ + id: params.id, + select: args.select + }).unwrap(); } /** * Prefetch a single Post for SSR or cache warming * * @example * \`\`\`ts - * await prefetchPostQuery(queryClient, { id: 'some-id' }); + * await prefetchPostQuery(queryClient, { id: 'some-id', selection: { fields: { id: true } } }); * \`\`\` */ -export async function prefetchPostQuery(queryClient: QueryClient, variables: PostQueryVariables, scope?: PostScope, options?: ExecuteOptions): Promise { +export async function prefetchPostQuery(queryClient: QueryClient, params: { + id: string; + selection: { + fields: S; + } & StrictSelect; +} & { + scope?: PostScope; +}): Promise; +export async function prefetchPostQuery(queryClient: QueryClient, params: { + id: string; + selection: SelectionConfig; +} & { + scope?: PostScope; +}): Promise { + const args = buildSelectionArgs(params.selection); await queryClient.prefetchQuery({ - queryKey: postKeys.detail(variables.id, scope), - queryFn: () => execute(postQueryDocument, variables, options) + queryKey: postKeys.detail(params.id, params?.scope), + queryFn: () => getClient().post.findOne({ + id: params.id, + select: args.select + }).unwrap() }); -}" +} +" `; exports[`Query Hook Generators generateSingleQueryHook generates single query hook without centralized keys 1`] = ` @@ -1764,41 +2028,52 @@ exports[`Query Hook Generators generateSingleQueryHook generates single query ho */ import { useQuery } from "@tanstack/react-query"; -import type { UseQueryOptions, QueryClient } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { ExecuteOptions } from "../client"; -import type { User } from "../types"; -export type { User } from "../types"; -export const userQueryDocument = \` -query UserQuery($id: UUID!) { - user(id: $id) { - id - email - name - createdAt - } -} -\`; -export interface UserQueryVariables { - id: string; -} -export interface UserQueryResult { - user: User | null; -} +import type { UseQueryOptions, UseQueryResult, QueryClient } from "@tanstack/react-query"; +import { getClient } from "../client"; +import { buildSelectionArgs } from "../selection"; +import type { SelectionConfig } from "../selection"; +import type { UserSelect, UserWithRelations } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { UserSelect, UserWithRelations } from "../../orm/input-types"; export const userQueryKey = (id: string) => ["user", "detail", id] as const; /** * Query hook for fetching a single User * * @example * \`\`\`tsx - * const { data, isLoading } = useUserQuery({ id: 'some-id' }); + * const { data, isLoading } = useUserQuery({ + * id: 'some-id', + * selection: { fields: { id: true, name: true } }, + * }); * \`\`\` */ -export function useUserQuery(variables: UserQueryVariables, options?: Omit, 'queryKey' | 'queryFn'>) { +export function useUserQuery | null; +}>(params: { + id: string; + selection: { + fields: S; + } & StrictSelect; +} & Omit | null; +}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; +export function useUserQuery(params: { + id: string; + selection: SelectionConfig; +} & Omit, "queryKey" | "queryFn">) { + const args = buildSelectionArgs(params.selection); + const { + selection: _selection, + ...queryOptions + } = params ?? {}; + void _selection; return useQuery({ - queryKey: userQueryKey(variables.id), - queryFn: () => execute(userQueryDocument, variables), - ...options + queryKey: userQueryKey(params.id), + queryFn: () => getClient().user.findOne({ + id: params.id, + select: args.select + }).unwrap(), + ...queryOptions }); } /** @@ -1806,26 +2081,58 @@ export function useUserQuery(variables: UserQueryVariables, options?: Omit { - return execute(userQueryDocument, variables, options); +export async function fetchUserQuery(params: { + id: string; + selection: { + fields: S; + } & StrictSelect; +}): Promise<{ + user: InferSelectResult | null; +}>; +export async function fetchUserQuery(params: { + id: string; + selection: SelectionConfig; +}) { + const args = buildSelectionArgs(params.selection); + return getClient().user.findOne({ + id: params.id, + select: args.select + }).unwrap(); } /** * Prefetch a single User for SSR or cache warming * * @example * \`\`\`ts - * await prefetchUserQuery(queryClient, { id: 'some-id' }); + * await prefetchUserQuery(queryClient, { id: 'some-id', selection: { fields: { id: true } } }); * \`\`\` */ -export async function prefetchUserQuery(queryClient: QueryClient, variables: UserQueryVariables, options?: ExecuteOptions): Promise { +export async function prefetchUserQuery(queryClient: QueryClient, params: { + id: string; + selection: { + fields: S; + } & StrictSelect; +}): Promise; +export async function prefetchUserQuery(queryClient: QueryClient, params: { + id: string; + selection: SelectionConfig; +}): Promise { + const args = buildSelectionArgs(params.selection); await queryClient.prefetchQuery({ - queryKey: userQueryKey(variables.id), - queryFn: () => execute(userQueryDocument, variables, options) + queryKey: userQueryKey(params.id), + queryFn: () => getClient().user.findOne({ + id: params.id, + select: args.select + }).unwrap() }); -}" +} +" `; exports[`Schema Types Generator generateSchemaTypesFile generates schema types file with empty table types 1`] = ` diff --git a/graphql/codegen/src/__tests__/codegen/client-generator.test.ts b/graphql/codegen/src/__tests__/codegen/client-generator.test.ts index afcf275e4..aa8f54b04 100644 --- a/graphql/codegen/src/__tests__/codegen/client-generator.test.ts +++ b/graphql/codegen/src/__tests__/codegen/client-generator.test.ts @@ -4,12 +4,16 @@ * Tests the generated ORM client files: client.ts, query-builder.ts, select-types.ts, index.ts */ import { + generateCreateClientFile, generateOrmClientFile, generateQueryBuilderFile, generateSelectTypesFile, - generateCreateClientFile, } from '../../core/codegen/orm/client-generator'; -import type { CleanTable, CleanFieldType, CleanRelations } from '../../types/schema'; +import type { + CleanFieldType, + CleanRelations, + CleanTable, +} from '../../types/schema'; // ============================================================================ // Test Fixtures @@ -27,7 +31,9 @@ const emptyRelations: CleanRelations = { manyToMany: [], }; -function createTable(partial: Partial & { name: string }): CleanTable { +function createTable( + partial: Partial & { name: string }, +): CleanTable { return { name: partial.name, fields: partial.fields ?? [], @@ -91,12 +97,24 @@ describe('client-generator', () => { createTable({ name: 'User', fields: [{ name: 'id', type: fieldTypes.uuid }], - query: { all: 'users', one: 'user', create: 'createUser', update: 'updateUser', delete: 'deleteUser' }, + query: { + all: 'users', + one: 'user', + create: 'createUser', + update: 'updateUser', + delete: 'deleteUser', + }, }), createTable({ name: 'Post', fields: [{ name: 'id', type: fieldTypes.uuid }], - query: { all: 'posts', one: 'post', create: 'createPost', update: 'updatePost', delete: 'deletePost' }, + query: { + all: 'posts', + one: 'post', + create: 'createPost', + update: 'updatePost', + delete: 'deletePost', + }, }), ]; @@ -114,7 +132,13 @@ describe('client-generator', () => { createTable({ name: 'User', fields: [{ name: 'id', type: fieldTypes.uuid }], - query: { all: 'users', one: 'user', create: 'createUser', update: 'updateUser', delete: 'deleteUser' }, + query: { + all: 'users', + one: 'user', + create: 'createUser', + update: 'updateUser', + delete: 'deleteUser', + }, }), ]; @@ -123,8 +147,10 @@ describe('client-generator', () => { expect(result.content).toMatchSnapshot(); expect(result.content).toContain('createQueryOperations'); expect(result.content).toContain('createMutationOperations'); - expect(result.content).toContain("query: createQueryOperations(client)"); - expect(result.content).toContain("mutation: createMutationOperations(client)"); + expect(result.content).toContain('query: createQueryOperations(client)'); + expect(result.content).toContain( + 'mutation: createMutationOperations(client)', + ); }); }); }); diff --git a/graphql/codegen/src/__tests__/codegen/format-output.test.ts b/graphql/codegen/src/__tests__/codegen/format-output.test.ts index bb8b87099..35169f7fb 100644 --- a/graphql/codegen/src/__tests__/codegen/format-output.test.ts +++ b/graphql/codegen/src/__tests__/codegen/format-output.test.ts @@ -3,8 +3,9 @@ * Verifies that oxfmt formats generated code correctly */ import * as fs from 'node:fs'; -import * as path from 'node:path'; import * as os from 'node:os'; +import * as path from 'node:path'; + import { formatOutput } from '../../core/output'; describe('formatOutput', () => { diff --git a/graphql/codegen/src/__tests__/codegen/input-types-generator.test.ts b/graphql/codegen/src/__tests__/codegen/input-types-generator.test.ts index d509456fa..d8bf2a8a7 100644 --- a/graphql/codegen/src/__tests__/codegen/input-types-generator.test.ts +++ b/graphql/codegen/src/__tests__/codegen/input-types-generator.test.ts @@ -6,15 +6,19 @@ * used to validate the AST-based migration produces equivalent results. */ // Jest globals - no import needed -import { generateInputTypesFile, collectInputTypeNames, collectPayloadTypeNames } from '../../core/codegen/orm/input-types-generator'; +import { + collectInputTypeNames, + collectPayloadTypeNames, + generateInputTypesFile, +} from '../../core/codegen/orm/input-types-generator'; import type { - CleanTable, + CleanArgument, CleanFieldType, CleanRelations, - TypeRegistry, - ResolvedType, - CleanArgument, + CleanTable, CleanTypeRef, + ResolvedType, + TypeRegistry, } from '../../types/schema'; // ============================================================================ @@ -46,7 +50,9 @@ const emptyRelations: CleanRelations = { manyToMany: [], }; -function createTable(partial: Partial & { name: string }): CleanTable { +function createTable( + partial: Partial & { name: string }, +): CleanTable { return { name: partial.name, fields: partial.fields ?? [], @@ -61,7 +67,11 @@ function createTypeRegistry(types: Record): TypeRegistry { return new Map(Object.entries(types)); } -function createTypeRef(kind: CleanTypeRef['kind'], name: string | null, ofType?: CleanTypeRef): CleanTypeRef { +function createTypeRef( + kind: CleanTypeRef['kind'], + name: string | null, + ofType?: CleanTypeRef, +): CleanTypeRef { return { kind, name, ofType }; } @@ -317,7 +327,10 @@ const sampleTypeRegistry = createTypeRegistry({ name: 'LoginInput', inputFields: [ { name: 'email', type: createNonNull(createTypeRef('SCALAR', 'String')) }, - { name: 'password', type: createNonNull(createTypeRef('SCALAR', 'String')) }, + { + name: 'password', + type: createNonNull(createTypeRef('SCALAR', 'String')), + }, { name: 'rememberMe', type: createTypeRef('SCALAR', 'Boolean') }, ], }, @@ -326,7 +339,10 @@ const sampleTypeRegistry = createTypeRegistry({ name: 'RegisterInput', inputFields: [ { name: 'email', type: createNonNull(createTypeRef('SCALAR', 'String')) }, - { name: 'password', type: createNonNull(createTypeRef('SCALAR', 'String')) }, + { + name: 'password', + type: createNonNull(createTypeRef('SCALAR', 'String')), + }, { name: 'name', type: createTypeRef('SCALAR', 'String') }, ], }, @@ -376,14 +392,21 @@ describe('generateInputTypesFile', () => { it('generates custom input types from TypeRegistry', () => { const usedInputTypes = new Set(['LoginInput', 'RegisterInput', 'UserRole']); - const result = generateInputTypesFile(sampleTypeRegistry, usedInputTypes, [userTable]); + const result = generateInputTypesFile(sampleTypeRegistry, usedInputTypes, [ + userTable, + ]); expect(result.content).toMatchSnapshot(); }); it('generates payload types for custom operations', () => { const usedInputTypes = new Set(['LoginInput']); const usedPayloadTypes = new Set(['LoginPayload']); - const result = generateInputTypesFile(sampleTypeRegistry, usedInputTypes, [userTable], usedPayloadTypes); + const result = generateInputTypesFile( + sampleTypeRegistry, + usedInputTypes, + [userTable], + usedPayloadTypes, + ); expect(result.content).toMatchSnapshot(); }); @@ -447,20 +470,29 @@ describe('entity types', () => { expect(result.content).toContain('email?: string | null;'); expect(result.content).toContain('age?: number | null;'); expect(result.content).toContain('isActive?: boolean | null;'); - expect(result.content).toContain('metadata?: Record | null;'); + expect(result.content).toContain( + 'metadata?: Record | null;', + ); }); it('generates entity relations interface', () => { - const result = generateInputTypesFile(new Map(), new Set(), [userTableWithRelations, postTable]); + const result = generateInputTypesFile(new Map(), new Set(), [ + userTableWithRelations, + postTable, + ]); expect(result.content).toContain('export interface UserRelations {'); expect(result.content).toContain('posts?: ConnectionResult;'); }); it('generates WithRelations type alias', () => { - const result = generateInputTypesFile(new Map(), new Set(), [userTableWithRelations]); + const result = generateInputTypesFile(new Map(), new Set(), [ + userTableWithRelations, + ]); - expect(result.content).toContain('export type UserWithRelations = User & UserRelations;'); + expect(result.content).toContain( + 'export type UserWithRelations = User & UserRelations;', + ); }); }); @@ -479,7 +511,10 @@ describe('entity select types', () => { }); it('generates select type with belongsTo relation options', () => { - const result = generateInputTypesFile(new Map(), new Set(), [postTable, userTable]); + const result = generateInputTypesFile(new Map(), new Set(), [ + postTable, + userTable, + ]); expect(result.content).toContain('export type PostSelect = {'); // Babel generates multi-line format for object types @@ -488,7 +523,10 @@ describe('entity select types', () => { }); it('generates select type with hasMany relation options', () => { - const result = generateInputTypesFile(new Map(), new Set(), [userTableWithRelations, postTable]); + const result = generateInputTypesFile(new Map(), new Set(), [ + userTableWithRelations, + postTable, + ]); expect(result.content).toContain('posts?: boolean | {'); expect(result.content).toContain('select?: PostSelect;'); @@ -498,7 +536,10 @@ describe('entity select types', () => { }); it('generates select type with manyToMany relation options', () => { - const result = generateInputTypesFile(new Map(), new Set(), [categoryTable, postTable]); + const result = generateInputTypesFile(new Map(), new Set(), [ + categoryTable, + postTable, + ]); expect(result.content).toContain('export type CategorySelect = {'); expect(result.content).toContain('posts?: boolean | {'); @@ -594,7 +635,11 @@ describe('CRUD input types', () => { describe('custom input types', () => { it('generates input types from TypeRegistry', () => { const usedInputTypes = new Set(['LoginInput', 'RegisterInput']); - const result = generateInputTypesFile(sampleTypeRegistry, usedInputTypes, []); + const result = generateInputTypesFile( + sampleTypeRegistry, + usedInputTypes, + [], + ); expect(result.content).toContain('export interface LoginInput {'); expect(result.content).toContain('email: string;'); // Non-null @@ -604,10 +649,16 @@ describe('custom input types', () => { it('generates enum types from TypeRegistry', () => { const usedInputTypes = new Set(['UserRole']); - const result = generateInputTypesFile(sampleTypeRegistry, usedInputTypes, []); + const result = generateInputTypesFile( + sampleTypeRegistry, + usedInputTypes, + [], + ); // Babel generates double quotes for string literals - expect(result.content).toContain('export type UserRole = "ADMIN" | "USER" | "GUEST";'); + expect(result.content).toContain( + 'export type UserRole = "ADMIN" | "USER" | "GUEST";', + ); }); }); @@ -619,7 +670,12 @@ describe('payload types', () => { it('generates payload types for custom operations', () => { const usedInputTypes = new Set(); const usedPayloadTypes = new Set(['LoginPayload']); - const result = generateInputTypesFile(sampleTypeRegistry, usedInputTypes, [], usedPayloadTypes); + const result = generateInputTypesFile( + sampleTypeRegistry, + usedInputTypes, + [], + usedPayloadTypes, + ); expect(result.content).toContain('export interface LoginPayload {'); expect(result.content).toContain('token?: string | null;'); @@ -629,7 +685,12 @@ describe('payload types', () => { it('generates Select types for payload types', () => { const usedInputTypes = new Set(); const usedPayloadTypes = new Set(['LoginPayload']); - const result = generateInputTypesFile(sampleTypeRegistry, usedInputTypes, [], usedPayloadTypes); + const result = generateInputTypesFile( + sampleTypeRegistry, + usedInputTypes, + [], + usedPayloadTypes, + ); expect(result.content).toContain('export type LoginPayloadSelect = {'); expect(result.content).toContain('token?: boolean;'); @@ -646,12 +707,18 @@ describe('collectInputTypeNames', () => { const operations = [ { args: [ - { name: 'input', type: createNonNull(createTypeRef('INPUT_OBJECT', 'LoginInput')) }, + { + name: 'input', + type: createNonNull(createTypeRef('INPUT_OBJECT', 'LoginInput')), + }, ] as CleanArgument[], }, { args: [ - { name: 'data', type: createTypeRef('INPUT_OBJECT', 'RegisterInput') }, + { + name: 'data', + type: createTypeRef('INPUT_OBJECT', 'RegisterInput'), + }, ] as CleanArgument[], }, ]; @@ -690,14 +757,14 @@ describe('collectPayloadTypeNames', () => { expect(result.has('RegisterPayload')).toBe(true); }); - it('excludes Connection types', () => { + it('includes Connection types', () => { const operations = [ { returnType: createTypeRef('OBJECT', 'UsersConnection') }, ]; const result = collectPayloadTypeNames(operations); - expect(result.has('UsersConnection')).toBe(false); + expect(result.has('UsersConnection')).toBe(true); }); }); @@ -742,6 +809,8 @@ describe('edge cases', () => { // Should generate a fallback type // Babel comment format may have slight differences expect(result.content).toContain("Type 'UnknownType' not found in schema"); - expect(result.content).toContain('export type UnknownType = Record;'); + expect(result.content).toContain( + 'export type UnknownType = Record;', + ); }); }); diff --git a/graphql/codegen/src/__tests__/codegen/model-generator.test.ts b/graphql/codegen/src/__tests__/codegen/model-generator.test.ts index 1a27b9062..db74b3133 100644 --- a/graphql/codegen/src/__tests__/codegen/model-generator.test.ts +++ b/graphql/codegen/src/__tests__/codegen/model-generator.test.ts @@ -4,7 +4,11 @@ * Tests the generated model classes with findMany, findFirst, create, update, delete methods. */ import { generateModelFile } from '../../core/codegen/orm/model-generator'; -import type { CleanTable, CleanFieldType, CleanRelations } from '../../types/schema'; +import type { + CleanFieldType, + CleanRelations, + CleanTable, +} from '../../types/schema'; // ============================================================================ // Test Fixtures @@ -25,7 +29,9 @@ const emptyRelations: CleanRelations = { manyToMany: [], }; -function createTable(partial: Partial & { name: string }): CleanTable { +function createTable( + partial: Partial & { name: string }, +): CleanTable { return { name: partial.name, fields: partial.fields ?? [], diff --git a/graphql/codegen/src/__tests__/codegen/query-builder.test.ts b/graphql/codegen/src/__tests__/codegen/query-builder.test.ts index b91c420fc..89c10ad78 100644 --- a/graphql/codegen/src/__tests__/codegen/query-builder.test.ts +++ b/graphql/codegen/src/__tests__/codegen/query-builder.test.ts @@ -5,8 +5,8 @@ * Functions are re-implemented here to avoid ./client import issues. */ import * as t from 'gql-ast'; -import { parseType, print } from 'graphql'; import type { ArgumentNode, FieldNode, VariableDefinitionNode } from 'graphql'; +import { parseType, print } from 'graphql'; // ============================================================================ // Core functions from query-builder.ts (re-implemented for testing) @@ -37,38 +37,79 @@ function addVariable( spec: { varName: string; argName?: string; typeName: string; value: unknown }, definitions: VariableDefinitionNode[], args: ArgumentNode[], - variables: Record + variables: Record, ): void { if (spec.value === undefined) return; definitions.push( t.variableDefinition({ variable: t.variable({ name: spec.varName }), type: parseType(spec.typeName), - }) + }), ); args.push( t.argument({ name: spec.argName ?? spec.varName, value: t.variable({ name: spec.varName }), - }) + }), ); variables[spec.varName] = spec.value; } -function buildSelections(select: Record | undefined): FieldNode[] { +function buildSelections( + select: Record | undefined, + connectionFieldsMap?: Record>, + entityType?: string, +): FieldNode[] { if (!select) return []; const fields: FieldNode[] = []; + const entityConnections = entityType + ? connectionFieldsMap?.[entityType] + : undefined; + for (const [key, value] of Object.entries(select)) { + if (value === false || value === undefined) continue; if (value === true) { fields.push(t.field({ name: key })); - } else if (value && typeof value === 'object' && 'select' in value) { - const nested = value as { select: Record }; - fields.push( - t.field({ - name: key, - selectionSet: t.selectionSet({ selections: buildSelections(nested.select) }), - }) - ); + continue; + } + if (typeof value === 'object' && value !== null) { + const nested = value as { + select?: Record; + first?: number; + filter?: Record; + connection?: boolean; + }; + if (nested.select) { + const relatedEntityType = entityConnections?.[key]; + const nestedSelections = buildSelections( + nested.select, + connectionFieldsMap, + relatedEntityType, + ); + const isConnection = + nested.connection === true || + nested.first !== undefined || + nested.filter !== undefined || + relatedEntityType !== undefined; + + if (isConnection) { + fields.push( + t.field({ + name: key, + selectionSet: t.selectionSet({ + selections: buildConnectionSelections(nestedSelections), + }), + }), + ); + } else { + fields.push( + t.field({ + name: key, + selectionSet: t.selectionSet({ selections: nestedSelections }), + }), + ); + } + } } } return fields; @@ -80,31 +121,64 @@ function buildFindManyDocument( select: TSelect, args: { where?: TWhere; first?: number; orderBy?: string[] }, filterTypeName: string, - orderByTypeName: string + orderByTypeName: string, + connectionFieldsMap?: Record>, ): { document: string; variables: Record } { const selections = select - ? buildSelections(select as Record) + ? buildSelections( + select as Record, + connectionFieldsMap, + operationName, + ) : [t.field({ name: 'id' })]; const variableDefinitions: VariableDefinitionNode[] = []; const queryArgs: ArgumentNode[] = []; const variables: Record = {}; - addVariable({ varName: 'where', argName: 'filter', typeName: filterTypeName, value: args.where }, variableDefinitions, queryArgs, variables); - addVariable({ varName: 'orderBy', typeName: `[${orderByTypeName}!]`, value: args.orderBy?.length ? args.orderBy : undefined }, variableDefinitions, queryArgs, variables); - addVariable({ varName: 'first', typeName: 'Int', value: args.first }, variableDefinitions, queryArgs, variables); + addVariable( + { + varName: 'where', + argName: 'filter', + typeName: filterTypeName, + value: args.where, + }, + variableDefinitions, + queryArgs, + variables, + ); + addVariable( + { + varName: 'orderBy', + typeName: `[${orderByTypeName}!]`, + value: args.orderBy?.length ? args.orderBy : undefined, + }, + variableDefinitions, + queryArgs, + variables, + ); + addVariable( + { varName: 'first', typeName: 'Int', value: args.first }, + variableDefinitions, + queryArgs, + variables, + ); const document = t.document({ definitions: [ t.operationDefinition({ operation: 'query', name: operationName + 'Query', - variableDefinitions: variableDefinitions.length ? variableDefinitions : undefined, + variableDefinitions: variableDefinitions.length + ? variableDefinitions + : undefined, selectionSet: t.selectionSet({ selections: [ t.field({ name: queryField, args: queryArgs.length ? queryArgs : undefined, - selectionSet: t.selectionSet({ selections: buildConnectionSelections(selections) }), + selectionSet: t.selectionSet({ + selections: buildConnectionSelections(selections), + }), }), ], }), @@ -119,7 +193,7 @@ function buildMutationDocument( mutationField: string, entityField: string, selections: FieldNode[], - inputTypeName: string + inputTypeName: string, ): string { return print( t.document({ @@ -137,7 +211,12 @@ function buildMutationDocument( selections: [ t.field({ name: mutationField, - args: [t.argument({ name: 'input', value: t.variable({ name: 'input' }) })], + args: [ + t.argument({ + name: 'input', + value: t.variable({ name: 'input' }), + }), + ], selectionSet: t.selectionSet({ selections: [ t.field({ @@ -151,7 +230,7 @@ function buildMutationDocument( }), }), ], - }) + }), ); } @@ -175,6 +254,164 @@ describe('query-builder', () => { expect(result[2].name.value).toBe('profile'); expect(result[2].selectionSet?.selections).toHaveLength(1); }); + + it('wraps connection fields in nodes when connectionFieldsMap is provided', () => { + const connectionFieldsMap = { + User: { posts: 'Post', comments: 'Comment' }, + }; + + const result = buildSelections( + { id: true, posts: { select: { id: true, title: true } } }, + connectionFieldsMap, + 'User', + ); + + expect(result).toHaveLength(2); + expect(result[0].name.value).toBe('id'); + expect(result[1].name.value).toBe('posts'); + // Should be wrapped in connection structure: nodes, totalCount, pageInfo + const postsSelections = result[1].selectionSet?.selections as FieldNode[]; + expect(postsSelections).toHaveLength(3); + expect(postsSelections[0].name.value).toBe('nodes'); + expect(postsSelections[1].name.value).toBe('totalCount'); + expect(postsSelections[2].name.value).toBe('pageInfo'); + // nodes should contain the actual fields + const nodesSelections = postsSelections[0].selectionSet + ?.selections as FieldNode[]; + expect(nodesSelections).toHaveLength(2); + expect(nodesSelections[0].name.value).toBe('id'); + expect(nodesSelections[1].name.value).toBe('title'); + }); + + it('does not wrap singular relations in nodes', () => { + const connectionFieldsMap = { + Post: { comments: 'Comment' }, + }; + + const result = buildSelections( + { id: true, author: { select: { id: true, name: true } } }, + connectionFieldsMap, + 'Post', + ); + + expect(result).toHaveLength(2); + expect(result[1].name.value).toBe('author'); + // author is NOT in connectionFieldsMap for Post → should NOT be wrapped + const authorSelections = result[1].selectionSet + ?.selections as FieldNode[]; + expect(authorSelections).toHaveLength(2); + expect(authorSelections[0].name.value).toBe('id'); + expect(authorSelections[1].name.value).toBe('name'); + }); + + it('handles deeply nested connections recursively', () => { + const connectionFieldsMap = { + User: { posts: 'Post' }, + Post: { comments: 'Comment' }, + }; + + const result = buildSelections( + { + id: true, + posts: { + select: { + id: true, + comments: { select: { id: true, body: true } }, + }, + }, + }, + connectionFieldsMap, + 'User', + ); + + // posts should be wrapped (User.posts is a connection) + const postsSelections = result[1].selectionSet?.selections as FieldNode[]; + expect(postsSelections[0].name.value).toBe('nodes'); + + // Inside nodes, comments should also be wrapped (Post.comments is a connection) + const nodesFields = postsSelections[0].selectionSet + ?.selections as FieldNode[]; + const commentsField = nodesFields.find( + (f) => f.name.value === 'comments', + )!; + const commentsSelections = commentsField.selectionSet + ?.selections as FieldNode[]; + expect(commentsSelections[0].name.value).toBe('nodes'); + expect(commentsSelections[1].name.value).toBe('totalCount'); + expect(commentsSelections[2].name.value).toBe('pageInfo'); + }); + + it('works without connectionFieldsMap (backward compat)', () => { + const result = buildSelections({ + id: true, + posts: { select: { id: true } }, + }); + + expect(result).toHaveLength(2); + expect(result[1].name.value).toBe('posts'); + // Without map, posts is NOT treated as a connection + const postsSelections = result[1].selectionSet?.selections as FieldNode[]; + expect(postsSelections).toHaveLength(1); + expect(postsSelections[0].name.value).toBe('id'); + }); + + it('still wraps when first/filter provided even without connectionFieldsMap', () => { + const result = buildSelections({ + id: true, + posts: { select: { id: true }, first: 10 }, + }); + + expect(result).toHaveLength(2); + const postsSelections = result[1].selectionSet?.selections as FieldNode[]; + expect(postsSelections[0].name.value).toBe('nodes'); + expect(postsSelections[1].name.value).toBe('totalCount'); + }); + + it('handles mixed connection and singular relations on same entity', () => { + const connectionFieldsMap = { + Post: { comments: 'Comment' }, + }; + + const result = buildSelections( + { + id: true, + author: { select: { id: true } }, + comments: { select: { id: true, body: true } }, + }, + connectionFieldsMap, + 'Post', + ); + + expect(result).toHaveLength(3); + // author = singular → no wrapping + const authorSelections = result[1].selectionSet + ?.selections as FieldNode[]; + expect(authorSelections[0].name.value).toBe('id'); + + // comments = connection → wrapped + const commentsSelections = result[2].selectionSet + ?.selections as FieldNode[]; + expect(commentsSelections[0].name.value).toBe('nodes'); + expect(commentsSelections[1].name.value).toBe('totalCount'); + }); + + it('handles entity not in connectionFieldsMap gracefully', () => { + const connectionFieldsMap = { + User: { posts: 'Post' }, + }; + + // Comment is not in the map — all nested fields should be singular + const result = buildSelections( + { id: true, author: { select: { id: true } } }, + connectionFieldsMap, + 'Comment', + ); + + expect(result).toHaveLength(2); + const authorSelections = result[1].selectionSet + ?.selections as FieldNode[]; + expect(authorSelections[0].name.value).toBe('id'); + }); }); describe('buildFindManyDocument', () => { @@ -183,9 +420,13 @@ describe('query-builder', () => { 'Users', 'users', { id: true, name: true }, - { where: { status: { equalTo: 'active' } }, first: 10, orderBy: ['NAME_ASC'] }, + { + where: { status: { equalTo: 'active' } }, + first: 10, + orderBy: ['NAME_ASC'], + }, 'UserFilter', - 'UsersOrderBy' + 'UsersOrderBy', ); expect(document).toContain('query UsersQuery'); @@ -211,7 +452,7 @@ describe('query-builder', () => { 'createUser', 'user', [t.field({ name: 'id' }), t.field({ name: 'name' })], - 'CreateUserInput' + 'CreateUserInput', ); expect(document).toContain('mutation CreateUserMutation'); @@ -222,4 +463,148 @@ describe('query-builder', () => { expect(document).toContain('name'); }); }); + + // ========================================================================== + // Snapshot Tests — GraphQL Document Output + // ========================================================================== + + describe('snapshots', () => { + const connectionFieldsMap = { + User: { posts: 'Post', comments: 'Comment' }, + Post: { comments: 'Comment', tags: 'Tag' }, + }; + + /** Helper: build a query document and print it for snapshotting */ + function buildQuerySnapshot( + select: Record, + map?: Record>, + ): string { + const selections = buildSelections(select, map, 'User'); + const doc = t.document({ + definitions: [ + t.operationDefinition({ + operation: 'query', + name: 'TestQuery', + selectionSet: t.selectionSet({ + selections: [ + t.field({ + name: 'users', + selectionSet: t.selectionSet({ + selections: buildConnectionSelections(selections), + }), + }), + ], + }), + }), + ], + }); + return print(doc); + } + + it('findMany with nested connection fields', () => { + const document = buildQuerySnapshot( + { + id: true, + name: true, + posts: { select: { id: true, title: true, body: true } }, + }, + connectionFieldsMap, + ); + expect(document).toMatchSnapshot(); + }); + + it('findMany with deeply nested connections (3 levels)', () => { + const document = buildQuerySnapshot( + { + id: true, + posts: { + select: { + id: true, + title: true, + comments: { + select: { id: true, body: true }, + }, + }, + }, + }, + connectionFieldsMap, + ); + expect(document).toMatchSnapshot(); + }); + + it('findMany with mixed connection and singular relations', () => { + const document = buildQuerySnapshot( + { + id: true, + name: true, + profile: { select: { bio: true, avatar: true } }, + posts: { select: { id: true, title: true } }, + comments: { select: { id: true, body: true } }, + }, + connectionFieldsMap, + ); + expect(document).toMatchSnapshot(); + }); + + it('findMany without connectionFieldsMap (no wrapping)', () => { + const document = buildQuerySnapshot( + { + id: true, + name: true, + posts: { select: { id: true, title: true } }, + }, + // no connectionFieldsMap + ); + expect(document).toMatchSnapshot(); + }); + + it('findMany document with filter and pagination', () => { + const { document } = buildFindManyDocument( + 'User', + 'users', + { id: true, name: true, email: true }, + { + where: { name: { equalTo: 'test' } }, + first: 25, + orderBy: ['NAME_ASC', 'CREATED_AT_DESC'], + }, + 'UserFilter', + 'UsersOrderBy', + ); + expect(document).toMatchSnapshot(); + }); + + it('mutation document', () => { + const document = buildMutationDocument( + 'CreateUser', + 'createUser', + 'user', + [ + t.field({ name: 'id' }), + t.field({ name: 'name' }), + t.field({ name: 'email' }), + ], + 'CreateUserInput', + ); + expect(document).toMatchSnapshot(); + }); + + it('findMany document with nested connections via connectionFieldsMap', () => { + const { document } = buildFindManyDocument( + 'User', + 'users', + { + id: true, + name: true, + posts: { select: { id: true, title: true } }, + comments: { select: { id: true } }, + }, + {}, + 'UserFilter', + 'UsersOrderBy', + connectionFieldsMap, + ); + expect(document).toMatchSnapshot(); + }); + }); }); diff --git a/graphql/codegen/src/__tests__/codegen/query-keys-factory.test.ts b/graphql/codegen/src/__tests__/codegen/query-keys-factory.test.ts index abc8484b9..6a23588ba 100644 --- a/graphql/codegen/src/__tests__/codegen/query-keys-factory.test.ts +++ b/graphql/codegen/src/__tests__/codegen/query-keys-factory.test.ts @@ -6,11 +6,17 @@ * - Mutation keys factory (mutation-keys.ts) * - Cache invalidation helpers (invalidation.ts) */ -import { generateQueryKeysFile } from '../../core/codegen/query-keys'; -import { generateMutationKeysFile } from '../../core/codegen/mutation-keys'; import { generateInvalidationFile } from '../../core/codegen/invalidation'; -import type { CleanTable, CleanFieldType, CleanRelations, CleanOperation, CleanTypeRef } from '../../types/schema'; -import type { QueryKeyConfig, EntityRelationship } from '../../types/config'; +import { generateMutationKeysFile } from '../../core/codegen/mutation-keys'; +import { generateQueryKeysFile } from '../../core/codegen/query-keys'; +import type { EntityRelationship, QueryKeyConfig } from '../../types/config'; +import type { + CleanFieldType, + CleanOperation, + CleanRelations, + CleanTable, + CleanTypeRef, +} from '../../types/schema'; const fieldTypes = { uuid: { gqlType: 'UUID', isArray: false } as CleanFieldType, @@ -26,7 +32,9 @@ const emptyRelations: CleanRelations = { manyToMany: [], }; -function createTable(partial: Partial & { name: string }): CleanTable { +function createTable( + partial: Partial & { name: string }, +): CleanTable { return { name: partial.name, fields: partial.fields ?? [], @@ -37,7 +45,11 @@ function createTable(partial: Partial & { name: string }): CleanTabl }; } -function createTypeRef(kind: CleanTypeRef['kind'], name: string | null, ofType?: CleanTypeRef): CleanTypeRef { +function createTypeRef( + kind: CleanTypeRef['kind'], + name: string | null, + ofType?: CleanTypeRef, +): CleanTypeRef { return { kind, name, ofType }; } @@ -155,8 +167,16 @@ const simpleRelationships: Record = { const hierarchicalRelationships: Record = { database: { parent: 'Organization', foreignKey: 'organizationId' }, - table: { parent: 'Database', foreignKey: 'databaseId', ancestors: ['organization'] }, - field: { parent: 'Table', foreignKey: 'tableId', ancestors: ['database', 'organization'] }, + table: { + parent: 'Database', + foreignKey: 'databaseId', + ancestors: ['organization'], + }, + field: { + parent: 'Table', + foreignKey: 'tableId', + ancestors: ['database', 'organization'], + }, }; const sampleCustomQueries: CleanOperation[] = [ @@ -171,7 +191,14 @@ const sampleCustomQueries: CleanOperation[] = [ name: 'searchUsers', kind: 'query', args: [ - { name: 'query', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) }, + { + name: 'query', + type: createTypeRef( + 'NON_NULL', + null, + createTypeRef('SCALAR', 'String'), + ), + }, { name: 'limit', type: createTypeRef('SCALAR', 'Int') }, ], returnType: createTypeRef('LIST', null, createTypeRef('OBJECT', 'User')), @@ -184,8 +211,22 @@ const sampleCustomMutations: CleanOperation[] = [ name: 'login', kind: 'mutation', args: [ - { name: 'email', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) }, - { name: 'password', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) }, + { + name: 'email', + type: createTypeRef( + 'NON_NULL', + null, + createTypeRef('SCALAR', 'String'), + ), + }, + { + name: 'password', + type: createTypeRef( + 'NON_NULL', + null, + createTypeRef('SCALAR', 'String'), + ), + }, ], returnType: createTypeRef('OBJECT', 'LoginPayload'), description: 'Authenticate user', diff --git a/graphql/codegen/src/__tests__/codegen/react-query-hooks.test.ts b/graphql/codegen/src/__tests__/codegen/react-query-hooks.test.ts index d5e273df6..cd77501e4 100644 --- a/graphql/codegen/src/__tests__/codegen/react-query-hooks.test.ts +++ b/graphql/codegen/src/__tests__/codegen/react-query-hooks.test.ts @@ -9,26 +9,33 @@ * - Schema types * - Barrel files */ -import { generateListQueryHook, generateSingleQueryHook } from '../../core/codegen/queries'; -import { generateCreateMutationHook, generateUpdateMutationHook, generateDeleteMutationHook } from '../../core/codegen/mutations'; -import { generateCustomQueryHook } from '../../core/codegen/custom-queries'; -import { generateCustomMutationHook } from '../../core/codegen/custom-mutations'; -import { generateSchemaTypesFile } from '../../core/codegen/schema-types-generator'; import { - generateQueriesBarrel, - generateMutationsBarrel, - generateMainBarrel, - generateCustomQueriesBarrel, generateCustomMutationsBarrel, + generateCustomQueriesBarrel, + generateMainBarrel, + generateMutationsBarrel, + generateQueriesBarrel, } from '../../core/codegen/barrel'; +import { generateCustomMutationHook } from '../../core/codegen/custom-mutations'; +import { generateCustomQueryHook } from '../../core/codegen/custom-queries'; +import { + generateCreateMutationHook, + generateDeleteMutationHook, + generateUpdateMutationHook, +} from '../../core/codegen/mutations'; +import { + generateListQueryHook, + generateSingleQueryHook, +} from '../../core/codegen/queries'; +import { generateSchemaTypesFile } from '../../core/codegen/schema-types-generator'; import type { - CleanTable, CleanFieldType, - CleanRelations, CleanOperation, + CleanRelations, + CleanTable, CleanTypeRef, - TypeRegistry, ResolvedType, + TypeRegistry, } from '../../types/schema'; const fieldTypes = { @@ -46,7 +53,9 @@ const emptyRelations: CleanRelations = { manyToMany: [], }; -function createTable(partial: Partial & { name: string }): CleanTable { +function createTable( + partial: Partial & { name: string }, +): CleanTable { return { name: partial.name, fields: partial.fields ?? [], @@ -57,7 +66,11 @@ function createTable(partial: Partial & { name: string }): CleanTabl }; } -function createTypeRef(kind: CleanTypeRef['kind'], name: string | null, ofType?: CleanTypeRef): CleanTypeRef { +function createTypeRef( + kind: CleanTypeRef['kind'], + name: string | null, + ofType?: CleanTypeRef, +): CleanTypeRef { return { kind, name, ofType }; } @@ -109,7 +122,14 @@ const simpleCustomQueries: CleanOperation[] = [ name: 'searchUsers', kind: 'query', args: [ - { name: 'query', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) }, + { + name: 'query', + type: createTypeRef( + 'NON_NULL', + null, + createTypeRef('SCALAR', 'String'), + ), + }, { name: 'limit', type: createTypeRef('SCALAR', 'Int') }, ], returnType: createTypeRef('LIST', null, createTypeRef('OBJECT', 'User')), @@ -122,8 +142,22 @@ const simpleCustomMutations: CleanOperation[] = [ name: 'login', kind: 'mutation', args: [ - { name: 'email', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) }, - { name: 'password', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) }, + { + name: 'email', + type: createTypeRef( + 'NON_NULL', + null, + createTypeRef('SCALAR', 'String'), + ), + }, + { + name: 'password', + type: createTypeRef( + 'NON_NULL', + null, + createTypeRef('SCALAR', 'String'), + ), + }, ], returnType: createTypeRef('OBJECT', 'LoginPayload'), description: 'Authenticate user', @@ -139,7 +173,14 @@ const simpleCustomMutations: CleanOperation[] = [ name: 'register', kind: 'mutation', args: [ - { name: 'input', type: createTypeRef('NON_NULL', null, createTypeRef('INPUT_OBJECT', 'RegisterInput')) }, + { + name: 'input', + type: createTypeRef( + 'NON_NULL', + null, + createTypeRef('INPUT_OBJECT', 'RegisterInput'), + ), + }, ], returnType: createTypeRef('OBJECT', 'RegisterPayload'), description: 'Register a new user', @@ -161,9 +202,7 @@ function createTypeRegistry(): TypeRegistry { registry.set('LogoutPayload', { kind: 'OBJECT', name: 'LogoutPayload', - fields: [ - { name: 'success', type: createTypeRef('SCALAR', 'Boolean') }, - ], + fields: [{ name: 'success', type: createTypeRef('SCALAR', 'Boolean') }], } as ResolvedType); registry.set('RegisterPayload', { @@ -179,8 +218,22 @@ function createTypeRegistry(): TypeRegistry { kind: 'INPUT_OBJECT', name: 'RegisterInput', inputFields: [ - { name: 'email', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) }, - { name: 'password', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) }, + { + name: 'email', + type: createTypeRef( + 'NON_NULL', + null, + createTypeRef('SCALAR', 'String'), + ), + }, + { + name: 'password', + type: createTypeRef( + 'NON_NULL', + null, + createTypeRef('SCALAR', 'String'), + ), + }, { name: 'name', type: createTypeRef('SCALAR', 'String') }, ], } as ResolvedType); @@ -194,9 +247,7 @@ function createTypeRegistry(): TypeRegistry { registry.set('Query', { kind: 'OBJECT', name: 'Query', - fields: [ - { name: 'currentUser', type: createTypeRef('OBJECT', 'User') }, - ], + fields: [{ name: 'currentUser', type: createTypeRef('OBJECT', 'User') }], } as ResolvedType); registry.set('Mutation', { @@ -301,7 +352,6 @@ describe('Mutation Hook Generators', () => { const result = generateCreateMutationHook(postTable, { reactQueryEnabled: true, useCentralizedKeys: true, - hasRelationships: true, }); expect(result).not.toBeNull(); expect(result!.content).toMatchSnapshot(); @@ -332,7 +382,6 @@ describe('Mutation Hook Generators', () => { const result = generateUpdateMutationHook(postTable, { reactQueryEnabled: true, useCentralizedKeys: true, - hasRelationships: true, }); expect(result).not.toBeNull(); expect(result!.content).toMatchSnapshot(); @@ -363,7 +412,6 @@ describe('Mutation Hook Generators', () => { const result = generateDeleteMutationHook(postTable, { reactQueryEnabled: true, useCentralizedKeys: true, - hasRelationships: true, }); expect(result).not.toBeNull(); expect(result!.content).toMatchSnapshot(); @@ -503,7 +551,6 @@ describe('Barrel File Generators', () => { describe('generateMainBarrel', () => { it('generates main barrel with all options enabled', () => { const result = generateMainBarrel([simpleUserTable, postTable], { - hasSchemaTypes: true, hasMutations: true, hasQueryKeys: true, hasMutationKeys: true, @@ -514,7 +561,6 @@ describe('Barrel File Generators', () => { it('generates main barrel without custom operations', () => { const result = generateMainBarrel([simpleUserTable], { - hasSchemaTypes: false, hasMutations: true, }); expect(result).toMatchSnapshot(); @@ -522,7 +568,6 @@ describe('Barrel File Generators', () => { it('generates main barrel without mutations', () => { const result = generateMainBarrel([simpleUserTable, postTable], { - hasSchemaTypes: true, hasMutations: false, }); expect(result).toMatchSnapshot(); @@ -532,7 +577,10 @@ describe('Barrel File Generators', () => { describe('generateCustomQueriesBarrel', () => { it('generates custom queries barrel', () => { const customQueryNames = simpleCustomQueries.map((q) => q.name); - const result = generateCustomQueriesBarrel([simpleUserTable], customQueryNames); + const result = generateCustomQueriesBarrel( + [simpleUserTable], + customQueryNames, + ); expect(result).toMatchSnapshot(); }); }); @@ -540,7 +588,10 @@ describe('Barrel File Generators', () => { describe('generateCustomMutationsBarrel', () => { it('generates custom mutations barrel', () => { const customMutationNames = simpleCustomMutations.map((m) => m.name); - const result = generateCustomMutationsBarrel([simpleUserTable], customMutationNames); + const result = generateCustomMutationsBarrel( + [simpleUserTable], + customMutationNames, + ); expect(result).toMatchSnapshot(); }); }); diff --git a/graphql/codegen/src/__tests__/codegen/react-query-optional.test.ts b/graphql/codegen/src/__tests__/codegen/react-query-optional.test.ts index cf21047a6..79300323e 100644 --- a/graphql/codegen/src/__tests__/codegen/react-query-optional.test.ts +++ b/graphql/codegen/src/__tests__/codegen/react-query-optional.test.ts @@ -6,11 +6,33 @@ * - Mutation generators return null (since they require React Query) * - Standalone fetch functions are still generated for queries */ -import { generateListQueryHook, generateSingleQueryHook, generateAllQueryHooks } from '../../core/codegen/queries'; -import { generateCreateMutationHook, generateUpdateMutationHook, generateDeleteMutationHook, generateAllMutationHooks } from '../../core/codegen/mutations'; -import { generateCustomQueryHook, generateAllCustomQueryHooks } from '../../core/codegen/custom-queries'; -import { generateCustomMutationHook, generateAllCustomMutationHooks } from '../../core/codegen/custom-mutations'; -import type { CleanTable, CleanFieldType, CleanRelations, CleanOperation, CleanTypeRef, TypeRegistry } from '../../types/schema'; +import { + generateAllCustomMutationHooks, + generateCustomMutationHook, +} from '../../core/codegen/custom-mutations'; +import { + generateAllCustomQueryHooks, + generateCustomQueryHook, +} from '../../core/codegen/custom-queries'; +import { + generateAllMutationHooks, + generateCreateMutationHook, + generateDeleteMutationHook, + generateUpdateMutationHook, +} from '../../core/codegen/mutations'; +import { + generateAllQueryHooks, + generateListQueryHook, + generateSingleQueryHook, +} from '../../core/codegen/queries'; +import type { + CleanFieldType, + CleanOperation, + CleanRelations, + CleanTable, + CleanTypeRef, + TypeRegistry, +} from '../../types/schema'; // ============================================================================ // Test Fixtures @@ -30,7 +52,9 @@ const emptyRelations: CleanRelations = { manyToMany: [], }; -function createTable(partial: Partial & { name: string }): CleanTable { +function createTable( + partial: Partial & { name: string }, +): CleanTable { return { name: partial.name, fields: partial.fields ?? [], @@ -58,7 +82,11 @@ const userTable = createTable({ }, }); -function createTypeRef(kind: CleanTypeRef['kind'], name: string | null, ofType?: CleanTypeRef): CleanTypeRef { +function createTypeRef( + kind: CleanTypeRef['kind'], + name: string | null, + ofType?: CleanTypeRef, +): CleanTypeRef { return { kind, name, ofType }; } @@ -74,8 +102,14 @@ const sampleMutationOperation: CleanOperation = { name: 'login', kind: 'mutation', args: [ - { name: 'email', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) }, - { name: 'password', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) }, + { + name: 'email', + type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')), + }, + { + name: 'password', + type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')), + }, ], returnType: createTypeRef('OBJECT', 'LoginPayload'), description: 'Authenticate user', @@ -90,64 +124,88 @@ const emptyTypeRegistry: TypeRegistry = new Map(); describe('Query generators with reactQueryEnabled: false', () => { describe('generateListQueryHook', () => { it('should not include React Query imports when disabled', () => { - const result = generateListQueryHook(userTable, { reactQueryEnabled: false }); + const result = generateListQueryHook(userTable, { + reactQueryEnabled: false, + }); expect(result.content).not.toContain('@tanstack/react-query'); expect(result.content).not.toContain('useQuery'); expect(result.content).not.toContain('UseQueryOptions'); }); it('should not include useXxxQuery hook when disabled', () => { - const result = generateListQueryHook(userTable, { reactQueryEnabled: false }); + const result = generateListQueryHook(userTable, { + reactQueryEnabled: false, + }); expect(result.content).not.toContain('export function useUsersQuery'); }); it('should not include prefetch function when disabled', () => { - const result = generateListQueryHook(userTable, { reactQueryEnabled: false }); - expect(result.content).not.toContain('export async function prefetchUsersQuery'); + const result = generateListQueryHook(userTable, { + reactQueryEnabled: false, + }); + expect(result.content).not.toContain( + 'export async function prefetchUsersQuery', + ); }); it('should still include standalone fetch function when disabled', () => { - const result = generateListQueryHook(userTable, { reactQueryEnabled: false }); + const result = generateListQueryHook(userTable, { + reactQueryEnabled: false, + }); expect(result.content).toContain('export async function fetchUsersQuery'); }); - it('should still include GraphQL document when disabled', () => { - const result = generateListQueryHook(userTable, { reactQueryEnabled: false }); - expect(result.content).toContain('usersQueryDocument'); + it('should still include ORM client imports when disabled', () => { + const result = generateListQueryHook(userTable, { + reactQueryEnabled: false, + }); + expect(result.content).toContain('getClient'); }); it('should still include query key factory when disabled', () => { - const result = generateListQueryHook(userTable, { reactQueryEnabled: false }); + const result = generateListQueryHook(userTable, { + reactQueryEnabled: false, + }); expect(result.content).toContain('usersQueryKey'); }); it('should update file header when disabled', () => { - const result = generateListQueryHook(userTable, { reactQueryEnabled: false }); + const result = generateListQueryHook(userTable, { + reactQueryEnabled: false, + }); expect(result.content).toContain('List query functions for User'); }); }); describe('generateSingleQueryHook', () => { it('should not include React Query imports when disabled', () => { - const result = generateSingleQueryHook(userTable, { reactQueryEnabled: false }); + const result = generateSingleQueryHook(userTable, { + reactQueryEnabled: false, + }); expect(result.content).not.toContain('@tanstack/react-query'); expect(result.content).not.toContain('useQuery'); }); it('should not include useXxxQuery hook when disabled', () => { - const result = generateSingleQueryHook(userTable, { reactQueryEnabled: false }); + const result = generateSingleQueryHook(userTable, { + reactQueryEnabled: false, + }); expect(result.content).not.toContain('export function useUserQuery'); }); it('should still include standalone fetch function when disabled', () => { - const result = generateSingleQueryHook(userTable, { reactQueryEnabled: false }); + const result = generateSingleQueryHook(userTable, { + reactQueryEnabled: false, + }); expect(result.content).toContain('export async function fetchUserQuery'); }); }); describe('generateAllQueryHooks', () => { it('should generate files without React Query when disabled', () => { - const results = generateAllQueryHooks([userTable], { reactQueryEnabled: false }); + const results = generateAllQueryHooks([userTable], { + reactQueryEnabled: false, + }); expect(results.length).toBe(2); // list + single for (const result of results) { expect(result.content).not.toContain('@tanstack/react-query'); @@ -176,7 +234,9 @@ describe('Query generators with reactQueryEnabled: true (default)', () => { it('should include prefetch function by default', () => { const result = generateListQueryHook(userTable); - expect(result.content).toContain('export async function prefetchUsersQuery'); + expect(result.content).toContain( + 'export async function prefetchUsersQuery', + ); }); it('should include standalone fetch function by default', () => { @@ -193,28 +253,36 @@ describe('Query generators with reactQueryEnabled: true (default)', () => { describe('Mutation generators with reactQueryEnabled: false', () => { describe('generateCreateMutationHook', () => { it('should return null when disabled', () => { - const result = generateCreateMutationHook(userTable, { reactQueryEnabled: false }); + const result = generateCreateMutationHook(userTable, { + reactQueryEnabled: false, + }); expect(result).toBeNull(); }); }); describe('generateUpdateMutationHook', () => { it('should return null when disabled', () => { - const result = generateUpdateMutationHook(userTable, { reactQueryEnabled: false }); + const result = generateUpdateMutationHook(userTable, { + reactQueryEnabled: false, + }); expect(result).toBeNull(); }); }); describe('generateDeleteMutationHook', () => { it('should return null when disabled', () => { - const result = generateDeleteMutationHook(userTable, { reactQueryEnabled: false }); + const result = generateDeleteMutationHook(userTable, { + reactQueryEnabled: false, + }); expect(result).toBeNull(); }); }); describe('generateAllMutationHooks', () => { it('should return empty array when disabled', () => { - const results = generateAllMutationHooks([userTable], { reactQueryEnabled: false }); + const results = generateAllMutationHooks([userTable], { + reactQueryEnabled: false, + }); expect(results).toEqual([]); }); }); @@ -263,7 +331,9 @@ describe('Custom query generators with reactQueryEnabled: false', () => { typeRegistry: emptyTypeRegistry, reactQueryEnabled: false, }); - expect(result.content).not.toContain('export function useCurrentUserQuery'); + expect(result.content).not.toContain( + 'export function useCurrentUserQuery', + ); }); it('should still include standalone fetch function when disabled', () => { @@ -272,7 +342,9 @@ describe('Custom query generators with reactQueryEnabled: false', () => { typeRegistry: emptyTypeRegistry, reactQueryEnabled: false, }); - expect(result.content).toContain('export async function fetchCurrentUserQuery'); + expect(result.content).toContain( + 'export async function fetchCurrentUserQuery', + ); }); }); diff --git a/graphql/codegen/src/__tests__/codegen/scalars.test.ts b/graphql/codegen/src/__tests__/codegen/scalars.test.ts index 27539d3f4..52165537f 100644 --- a/graphql/codegen/src/__tests__/codegen/scalars.test.ts +++ b/graphql/codegen/src/__tests__/codegen/scalars.test.ts @@ -2,12 +2,12 @@ * Tests for scalar mappings */ import { - SCALAR_TS_MAP, + BASE_FILTER_TYPE_NAMES, SCALAR_FILTER_MAP, SCALAR_NAMES, - BASE_FILTER_TYPE_NAMES, - scalarToTsType, + SCALAR_TS_MAP, scalarToFilterType, + scalarToTsType, } from '../../core/codegen/scalars'; describe('scalars', () => { @@ -81,11 +81,15 @@ describe('scalars', () => { }); it('returns unknown for unknown scalars when option set', () => { - expect(scalarToTsType('CustomScalar', { unknownScalar: 'unknown' })).toBe('unknown'); + expect(scalarToTsType('CustomScalar', { unknownScalar: 'unknown' })).toBe( + 'unknown', + ); }); it('uses overrides when provided', () => { - expect(scalarToTsType('JSON', { overrides: { JSON: 'JsonValue' } })).toBe('JsonValue'); + expect(scalarToTsType('JSON', { overrides: { JSON: 'JsonValue' } })).toBe( + 'JsonValue', + ); }); }); diff --git a/graphql/codegen/src/__tests__/codegen/schema-types-generator.test.ts b/graphql/codegen/src/__tests__/codegen/schema-types-generator.test.ts index 70fc56de2..4c8ef2a93 100644 --- a/graphql/codegen/src/__tests__/codegen/schema-types-generator.test.ts +++ b/graphql/codegen/src/__tests__/codegen/schema-types-generator.test.ts @@ -2,17 +2,33 @@ * Snapshot tests for schema-types-generator */ import { generateSchemaTypesFile } from '../../core/codegen/schema-types-generator'; -import type { TypeRegistry, ResolvedType } from '../../types/schema'; +import type { ResolvedType, TypeRegistry } from '../../types/schema'; -function createTypeRegistry(types: Array<[string, ResolvedType]>): TypeRegistry { +function createTypeRegistry( + types: Array<[string, ResolvedType]>, +): TypeRegistry { return new Map(types); } describe('schema-types-generator', () => { it('generates enum types as string unions', () => { const registry = createTypeRegistry([ - ['Status', { kind: 'ENUM', name: 'Status', enumValues: ['ACTIVE', 'INACTIVE', 'PENDING'] }], - ['Priority', { kind: 'ENUM', name: 'Priority', enumValues: ['LOW', 'MEDIUM', 'HIGH'] }], + [ + 'Status', + { + kind: 'ENUM', + name: 'Status', + enumValues: ['ACTIVE', 'INACTIVE', 'PENDING'], + }, + ], + [ + 'Priority', + { + kind: 'ENUM', + name: 'Priority', + enumValues: ['LOW', 'MEDIUM', 'HIGH'], + }, + ], ]); const result = generateSchemaTypesFile({ @@ -32,7 +48,14 @@ describe('schema-types-generator', () => { kind: 'INPUT_OBJECT', name: 'CreateUserInput', inputFields: [ - { name: 'email', type: { kind: 'NON_NULL', name: null, ofType: { kind: 'SCALAR', name: 'String' } } }, + { + name: 'email', + type: { + kind: 'NON_NULL', + name: null, + ofType: { kind: 'SCALAR', name: 'String' }, + }, + }, { name: 'name', type: { kind: 'SCALAR', name: 'String' } }, { name: 'age', type: { kind: 'SCALAR', name: 'Int' } }, ], @@ -44,7 +67,14 @@ describe('schema-types-generator', () => { kind: 'INPUT_OBJECT', name: 'UpdateUserInput', inputFields: [ - { name: 'id', type: { kind: 'NON_NULL', name: null, ofType: { kind: 'SCALAR', name: 'UUID' } } }, + { + name: 'id', + type: { + kind: 'NON_NULL', + name: null, + ofType: { kind: 'SCALAR', name: 'UUID' }, + }, + }, { name: 'name', type: { kind: 'SCALAR', name: 'String' } }, ], }, @@ -61,7 +91,14 @@ describe('schema-types-generator', () => { it('generates union types', () => { const registry = createTypeRegistry([ - ['SearchResult', { kind: 'UNION', name: 'SearchResult', possibleTypes: ['User', 'Post', 'Comment'] }], + [ + 'SearchResult', + { + kind: 'UNION', + name: 'SearchResult', + possibleTypes: ['User', 'Post', 'Comment'], + }, + ], ]); const result = generateSchemaTypesFile({ @@ -90,7 +127,14 @@ describe('schema-types-generator', () => { kind: 'OBJECT', name: 'LoginPayload', fields: [ - { name: 'token', type: { kind: 'NON_NULL', name: null, ofType: { kind: 'SCALAR', name: 'String' } } }, + { + name: 'token', + type: { + kind: 'NON_NULL', + name: null, + ofType: { kind: 'SCALAR', name: 'String' }, + }, + }, { name: 'refreshToken', type: { kind: 'SCALAR', name: 'String' } }, { name: 'user', type: { kind: 'OBJECT', name: 'User' } }, ], @@ -111,7 +155,14 @@ describe('schema-types-generator', () => { const registry = createTypeRegistry([ ['User', { kind: 'ENUM', name: 'User', enumValues: ['ADMIN'] }], ['String', { kind: 'ENUM', name: 'String', enumValues: ['A'] }], - ['CustomEnum', { kind: 'ENUM', name: 'CustomEnum', enumValues: ['VALUE_A', 'VALUE_B'] }], + [ + 'CustomEnum', + { + kind: 'ENUM', + name: 'CustomEnum', + enumValues: ['VALUE_A', 'VALUE_B'], + }, + ], ]); const result = generateSchemaTypesFile({ diff --git a/graphql/codegen/src/__tests__/codegen/utils.test.ts b/graphql/codegen/src/__tests__/codegen/utils.test.ts index 62dbf33a0..4dcb4ad08 100644 --- a/graphql/codegen/src/__tests__/codegen/utils.test.ts +++ b/graphql/codegen/src/__tests__/codegen/utils.test.ts @@ -2,19 +2,19 @@ * Tests for codegen utility functions */ import { + getFilterTypeName, + getGeneratedFileHeader, + getOrderByTypeName, + getPrimaryKeyInfo, + getTableNames, + gqlTypeToTs, lcFirst, - ucFirst, toCamelCase, toPascalCase, toScreamingSnake, - getTableNames, - getFilterTypeName, - getOrderByTypeName, - gqlTypeToTs, - getPrimaryKeyInfo, - getGeneratedFileHeader, + ucFirst, } from '../../core/codegen/utils'; -import type { CleanTable, CleanRelations } from '../../types/schema'; +import type { CleanRelations, CleanTable } from '../../types/schema'; const emptyRelations: CleanRelations = { belongsTo: [], @@ -24,7 +24,10 @@ const emptyRelations: CleanRelations = { }; // Use any for test fixture overrides to avoid strict type requirements -function createTable(name: string, overrides: Record = {}): CleanTable { +function createTable( + name: string, + overrides: Record = {}, +): CleanTable { return { name, fields: [], @@ -79,7 +82,7 @@ describe('utils', () => { const result = getTableNames( createTable('Person', { inflection: { tableFieldName: 'individual', allRows: 'people' }, - }) + }), ); expect(result.singularName).toBe('individual'); expect(result.pluralName).toBe('people'); @@ -88,8 +91,14 @@ describe('utils', () => { it('uses query.all for plural name', () => { const result = getTableNames( createTable('Child', { - query: { all: 'children', one: 'child', create: 'createChild', update: 'updateChild', delete: 'deleteChild' }, - }) + query: { + all: 'children', + one: 'child', + create: 'createChild', + update: 'updateChild', + delete: 'deleteChild', + }, + }), ); expect(result.pluralName).toBe('children'); }); @@ -98,12 +107,18 @@ describe('utils', () => { describe('type name generators', () => { it('getFilterTypeName returns correct filter type', () => { expect(getFilterTypeName(createTable('User'))).toBe('UserFilter'); - expect(getFilterTypeName(createTable('Post', { inflection: { filterType: 'PostCondition' } }))).toBe('PostCondition'); + expect( + getFilterTypeName( + createTable('Post', { inflection: { filterType: 'PostCondition' } }), + ), + ).toBe('PostCondition'); }); it('getOrderByTypeName returns correct orderBy type', () => { expect(getOrderByTypeName(createTable('User'))).toBe('UsersOrderBy'); - expect(getOrderByTypeName(createTable('Address'))).toBe('AddressesOrderBy'); + expect(getOrderByTypeName(createTable('Address'))).toBe( + 'AddressesOrderBy', + ); }); }); @@ -138,11 +153,20 @@ describe('utils', () => { it('extracts PK from constraints', () => { const table = createTable('User', { constraints: { - primaryKey: [{ name: 'users_pkey', fields: [{ name: 'id', type: { gqlType: 'UUID', isArray: false } }] }], + primaryKey: [ + { + name: 'users_pkey', + fields: [ + { name: 'id', type: { gqlType: 'UUID', isArray: false } }, + ], + }, + ], }, }); const result = getPrimaryKeyInfo(table); - expect(result).toEqual([{ name: 'id', gqlType: 'UUID', tsType: 'string' }]); + expect(result).toEqual([ + { name: 'id', gqlType: 'UUID', tsType: 'string' }, + ]); }); it('falls back to id field', () => { @@ -150,7 +174,9 @@ describe('utils', () => { fields: [{ name: 'id', type: { gqlType: 'UUID', isArray: false } }], }); const result = getPrimaryKeyInfo(table); - expect(result).toEqual([{ name: 'id', gqlType: 'UUID', tsType: 'string' }]); + expect(result).toEqual([ + { name: 'id', gqlType: 'UUID', tsType: 'string' }, + ]); }); it('handles composite keys', () => { diff --git a/graphql/codegen/src/__tests__/codegen/write-generated-files.test.ts b/graphql/codegen/src/__tests__/codegen/write-generated-files.test.ts new file mode 100644 index 000000000..cf39779a8 --- /dev/null +++ b/graphql/codegen/src/__tests__/codegen/write-generated-files.test.ts @@ -0,0 +1,61 @@ +import * as fs from 'node:fs'; +import * as os from 'node:os'; +import * as path from 'node:path'; + +import { writeGeneratedFiles } from '../../core/output'; + +describe('writeGeneratedFiles', () => { + let tempDir: string; + + beforeEach(() => { + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'codegen-write-test-')); + }); + + afterEach(() => { + fs.rmSync(tempDir, { recursive: true, force: true }); + }); + + it('removes stale TypeScript files when pruneStaleFiles is enabled', async () => { + const staleRoot = path.join(tempDir, 'stale.ts'); + const staleNested = path.join(tempDir, 'nested', 'old.ts'); + fs.mkdirSync(path.dirname(staleNested), { recursive: true }); + fs.writeFileSync(staleRoot, 'export const stale = true;\n'); + fs.writeFileSync(staleNested, 'export const old = true;\n'); + + const result = await writeGeneratedFiles( + [{ path: 'nested/new.ts', content: 'export const fresh = true;\n' }], + tempDir, + [], + { + showProgress: false, + formatFiles: false, + pruneStaleFiles: true, + }, + ); + + expect(result.success).toBe(true); + expect(fs.existsSync(staleRoot)).toBe(false); + expect(fs.existsSync(staleNested)).toBe(false); + expect(fs.existsSync(path.join(tempDir, 'nested', 'new.ts'))).toBe(true); + }); + + it('keeps existing files when pruneStaleFiles is disabled', async () => { + const staleRoot = path.join(tempDir, 'stale.ts'); + fs.writeFileSync(staleRoot, 'export const stale = true;\n'); + + const result = await writeGeneratedFiles( + [{ path: 'fresh.ts', content: 'export const fresh = true;\n' }], + tempDir, + [], + { + showProgress: false, + formatFiles: false, + pruneStaleFiles: false, + }, + ); + + expect(result.success).toBe(true); + expect(fs.existsSync(staleRoot)).toBe(true); + expect(fs.existsSync(path.join(tempDir, 'fresh.ts'))).toBe(true); + }); +}); diff --git a/graphql/codegen/src/__tests__/config/cli-shared.test.ts b/graphql/codegen/src/__tests__/config/cli-shared.test.ts new file mode 100644 index 000000000..db1900d26 --- /dev/null +++ b/graphql/codegen/src/__tests__/config/cli-shared.test.ts @@ -0,0 +1,39 @@ +import { + buildGenerateOptions, + seedArgvFromConfig, +} from '../../cli/shared'; + +describe('CLI shared utilities', () => { + it('preserves explicit false booleans from argv when merging with file config', () => { + const fileConfig = { + reactQuery: true, + orm: true, + dryRun: true, + }; + + const seeded = seedArgvFromConfig( + { reactQuery: false, orm: false }, + fileConfig, + ); + + expect(seeded).toMatchObject({ + reactQuery: false, + orm: false, + }); + }); + + it('normalizes list options through buildGenerateOptions in non-interactive flows', () => { + const options = buildGenerateOptions( + { + schemas: 'public, app', + apiNames: 'core, admin', + }, + {}, + ); + + expect(options.db).toEqual({ + schemas: ['public', 'app'], + apiNames: ['core', 'admin'], + }); + }); +}); diff --git a/graphql/codegen/src/__tests__/config/resolve-config.test.ts b/graphql/codegen/src/__tests__/config/resolve-config.test.ts index e7e879345..72a346bd0 100644 --- a/graphql/codegen/src/__tests__/config/resolve-config.test.ts +++ b/graphql/codegen/src/__tests__/config/resolve-config.test.ts @@ -1,10 +1,8 @@ -import type { - GraphQLSDKConfigTarget, -} from '../../types/config'; +import type { GraphQLSDKConfigTarget } from '../../types/config'; import { - mergeConfig, - getConfigOptions, DEFAULT_CONFIG, + getConfigOptions, + mergeConfig, } from '../../types/config'; describe('config resolution', () => { @@ -20,7 +18,9 @@ describe('config resolution', () => { expect(resolved.output).toBe(DEFAULT_CONFIG.output); expect(resolved.tables.include).toEqual(DEFAULT_CONFIG.tables.include); expect(resolved.queries.exclude).toEqual(DEFAULT_CONFIG.queries.exclude); - expect(resolved.queries.systemExclude).toEqual(DEFAULT_CONFIG.queries.systemExclude); + expect(resolved.queries.systemExclude).toEqual( + DEFAULT_CONFIG.queries.systemExclude, + ); }); it('merges nested config values with overrides', () => { diff --git a/graphql/codegen/src/__tests__/introspect/infer-tables.test.ts b/graphql/codegen/src/__tests__/introspect/infer-tables.test.ts index af8828802..810aa90c6 100644 --- a/graphql/codegen/src/__tests__/introspect/infer-tables.test.ts +++ b/graphql/codegen/src/__tests__/introspect/infer-tables.test.ts @@ -6,12 +6,12 @@ */ import { inferTablesFromIntrospection } from '../../core/introspect/infer-tables'; import type { + IntrospectionEnumValue, + IntrospectionField, + IntrospectionInputValue, IntrospectionQueryResponse, IntrospectionType, IntrospectionTypeRef, - IntrospectionField, - IntrospectionInputValue, - IntrospectionEnumValue, } from '../../types/introspection'; // ============================================================================ @@ -24,7 +24,7 @@ import type { function makeTypeRef( kind: 'SCALAR' | 'OBJECT' | 'INPUT_OBJECT' | 'ENUM' | 'LIST' | 'NON_NULL', name: string | null, - ofType?: IntrospectionTypeRef | null + ofType?: IntrospectionTypeRef | null, ): IntrospectionTypeRef { return { kind, name, ofType: ofType ?? null }; } @@ -89,7 +89,7 @@ interface TypeDef { function createIntrospection( types: TypeDef[], queryFields: FieldDef[] = [], - mutationFields: FieldDef[] = [] + mutationFields: FieldDef[] = [], ): IntrospectionQueryResponse { const makeField = (f: FieldDef): IntrospectionField => ({ name: f.name, @@ -100,7 +100,7 @@ function createIntrospection( type: a.type, description: null, defaultValue: null, - }) + }), ), deprecationReason: null, description: null, @@ -157,13 +157,13 @@ function createIntrospection( deprecationReason: null, description: null, isDeprecated: false, - }) + }), ) : null, interfaces: [], possibleTypes: null, description: null, - }) + }), ), ]; @@ -210,7 +210,7 @@ describe('Entity Detection', () => { [ // Query for users { name: 'users', type: object('UsersConnection') }, - ] + ], ); const tables = inferTablesFromIntrospection(introspection); @@ -245,7 +245,7 @@ describe('Entity Detection', () => { { name: 'users', type: object('UsersConnection') }, { name: 'posts', type: object('PostsConnection') }, { name: 'comments', type: object('CommentsConnection') }, - ] + ], ); const tables = inferTablesFromIntrospection(introspection); @@ -271,7 +271,7 @@ describe('Entity Detection', () => { fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], }, ], - [{ name: 'users', type: object('UsersConnection') }] + [{ name: 'users', type: object('UsersConnection') }], ); const tables = inferTablesFromIntrospection(introspection); @@ -302,7 +302,7 @@ describe('Field Extraction', () => { }, { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, ], - [{ name: 'users', type: object('UsersConnection') }] + [{ name: 'users', type: object('UsersConnection') }], ); const tables = inferTablesFromIntrospection(introspection); @@ -333,7 +333,7 @@ describe('Field Extraction', () => { }, { name: 'PostsConnection', kind: 'OBJECT', fields: [] }, ], - [{ name: 'posts', type: object('PostsConnection') }] + [{ name: 'posts', type: object('PostsConnection') }], ); const tables = inferTablesFromIntrospection(introspection); @@ -375,7 +375,7 @@ describe('Field Extraction', () => { { name: 'posts', type: object('PostsConnection') }, { name: 'users', type: object('UsersConnection') }, { name: 'comments', type: object('CommentsConnection') }, - ] + ], ); const tables = inferTablesFromIntrospection(introspection); @@ -416,7 +416,7 @@ describe('Relation Inference', () => { [ { name: 'posts', type: object('PostsConnection') }, { name: 'users', type: object('UsersConnection') }, - ] + ], ); const tables = inferTablesFromIntrospection(introspection); @@ -449,7 +449,7 @@ describe('Relation Inference', () => { [ { name: 'users', type: object('UsersConnection') }, { name: 'posts', type: object('PostsConnection') }, - ] + ], ); const tables = inferTablesFromIntrospection(introspection); @@ -486,7 +486,7 @@ describe('Relation Inference', () => { [ { name: 'categories', type: object('CategoriesConnection') }, { name: 'products', type: object('ProductsConnection') }, - ] + ], ); const tables = inferTablesFromIntrospection(introspection); @@ -495,7 +495,7 @@ describe('Relation Inference', () => { expect(categoryTable?.relations.manyToMany).toHaveLength(1); expect(categoryTable?.relations.manyToMany[0].rightTable).toBe('Product'); expect(categoryTable?.relations.manyToMany[0].junctionTable).toBe( - 'ProductCategory' + 'ProductCategory', ); }); }); @@ -515,7 +515,7 @@ describe('Query Operation Matching', () => { }, { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, ], - [{ name: 'allUsers', type: object('UsersConnection') }] + [{ name: 'allUsers', type: object('UsersConnection') }], ); const tables = inferTablesFromIntrospection(introspection); @@ -540,7 +540,7 @@ describe('Query Operation Matching', () => { type: object('User'), args: [{ name: 'id', type: nonNull(scalar('UUID')) }], }, - ] + ], ); const tables = inferTablesFromIntrospection(introspection); @@ -561,7 +561,7 @@ describe('Query Operation Matching', () => { [ { name: 'users', type: object('UsersConnection') }, // No single user query - ] + ], ); const tables = inferTablesFromIntrospection(introspection); @@ -593,7 +593,7 @@ describe('Mutation Operation Matching', () => { { name: 'input', type: nonNull(inputObject('CreateUserInput')) }, ], }, - ] + ], ); const tables = inferTablesFromIntrospection(introspection); @@ -629,7 +629,7 @@ describe('Mutation Operation Matching', () => { { name: 'input', type: nonNull(inputObject('DeleteUserInput')) }, ], }, - ] + ], ); const tables = inferTablesFromIntrospection(introspection); @@ -653,7 +653,7 @@ describe('Mutation Operation Matching', () => { [ { name: 'updateUserById', type: object('UpdateUserPayload') }, { name: 'updateUser', type: object('UpdateUserPayload') }, - ] + ], ); const tables = inferTablesFromIntrospection(introspection); @@ -677,7 +677,7 @@ describe('Constraint Inference', () => { }, { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, ], - [{ name: 'users', type: object('UsersConnection') }] + [{ name: 'users', type: object('UsersConnection') }], ); const tables = inferTablesFromIntrospection(introspection); @@ -702,7 +702,7 @@ describe('Constraint Inference', () => { }, ], [{ name: 'users', type: object('UsersConnection') }], - [{ name: 'updateUser', type: object('UpdateUserPayload') }] + [{ name: 'updateUser', type: object('UpdateUserPayload') }], ); const tables = inferTablesFromIntrospection(introspection); @@ -730,7 +730,7 @@ describe('Inflection Building', () => { { name: 'UserPatch', kind: 'INPUT_OBJECT', inputFields: [] }, { name: 'UpdateUserPayload', kind: 'OBJECT', fields: [] }, ], - [{ name: 'users', type: object('UsersConnection') }] + [{ name: 'users', type: object('UsersConnection') }], ); const tables = inferTablesFromIntrospection(introspection); @@ -755,7 +755,7 @@ describe('Inflection Building', () => { { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, // No UserFilter, UserPatch, or UpdateUserPayload ], - [{ name: 'users', type: object('UsersConnection') }] + [{ name: 'users', type: object('UsersConnection') }], ); const tables = inferTablesFromIntrospection(introspection); @@ -778,7 +778,7 @@ describe('Edge Cases', () => { // Only built-in types, no entities { name: 'PageInfo', kind: 'OBJECT', fields: [] }, ], - [] + [], ); const tables = inferTablesFromIntrospection(introspection); @@ -797,7 +797,7 @@ describe('Edge Cases', () => { }, { name: 'OrphansConnection', kind: 'OBJECT', fields: [] }, ], - [] // No query fields + [], // No query fields ); const tables = inferTablesFromIntrospection(introspection); @@ -831,7 +831,7 @@ describe('Edge Cases', () => { [ { name: 'users', type: object('UsersConnection') }, { name: 'posts', type: object('PostsConnection') }, - ] + ], ); // Should not cause infinite loops @@ -856,7 +856,7 @@ describe('Edge Cases', () => { }, { name: 'PeopleConnection', kind: 'OBJECT', fields: [] }, ], - [{ name: 'people', type: object('PeopleConnection') }] + [{ name: 'people', type: object('PeopleConnection') }], ); const tables = inferTablesFromIntrospection(introspection); @@ -885,7 +885,7 @@ describe('Edge Cases', () => { enumValues: ['ID_ASC', 'ID_DESC'], }, ], - [{ name: 'addresses', type: object('AddressesConnection') }] + [{ name: 'addresses', type: object('AddressesConnection') }], ); const tables = inferTablesFromIntrospection(introspection); @@ -908,7 +908,7 @@ describe('Edge Cases', () => { { name: 'CategoriesConnection', kind: 'OBJECT', fields: [] }, { name: 'CategoriesOrderBy', kind: 'ENUM', enumValues: ['ID_ASC'] }, ], - [{ name: 'categories', type: object('CategoriesConnection') }] + [{ name: 'categories', type: object('CategoriesConnection') }], ); const tables = inferTablesFromIntrospection(introspection); @@ -929,7 +929,7 @@ describe('Edge Cases', () => { // Schema has the actual OrderBy enum { name: 'StatusesOrderBy', kind: 'ENUM', enumValues: ['ID_ASC'] }, ], - [{ name: 'statuses', type: object('StatusesConnection') }] + [{ name: 'statuses', type: object('StatusesConnection') }], ); const tables = inferTablesFromIntrospection(introspection); diff --git a/graphql/codegen/src/cli/index.ts b/graphql/codegen/src/cli/index.ts index 5ef53ee8c..8ab33c45a 100644 --- a/graphql/codegen/src/cli/index.ts +++ b/graphql/codegen/src/cli/index.ts @@ -5,12 +5,21 @@ * This is a thin wrapper around the core generate() function. * All business logic is in the core modules. */ -import { CLI, CLIOptions, Inquirerer, getPackageJson } from 'inquirerer'; +import { CLI, CLIOptions, getPackageJson, Inquirerer } from 'inquirerer'; -import { generate } from '../core/generate'; import { findConfigFile, loadConfigFile } from '../core/config'; +import { generate } from '../core/generate'; import type { GraphQLSDKConfigTarget } from '../types/config'; -import { camelizeArgv, codegenQuestions, printResult, type CodegenAnswers } from './shared'; +import { + buildDbConfig, + buildGenerateOptions, + camelizeArgv, + codegenQuestions, + hasResolvedCodegenSource, + normalizeCodegenListOptions, + printResult, + seedArgvFromConfig, +} from './shared'; const usage = ` graphql-codegen - GraphQL SDK generator for Constructive databases @@ -33,8 +42,6 @@ Generator Options: -o, --output Output directory -t, --target Target name (for multi-target configs) -a, --authorization Authorization header value - --browser-compatible Generate browser-compatible code (default: true) - Set to false for Node.js with localhost DNS fix --dry-run Preview without writing files -v, --verbose Show detailed output @@ -45,7 +52,7 @@ Generator Options: export const commands = async ( argv: Record, prompter: Inquirerer, - _options: CLIOptions + _options: CLIOptions, ): Promise> => { if (argv.version) { const pkg = getPackageJson(__dirname); @@ -58,10 +65,21 @@ export const commands = async ( process.exit(0); } - const configPath = (argv.config || argv.c || findConfigFile()) as string | undefined; + const hasSourceFlags = Boolean( + argv.endpoint || + argv.e || + argv['schema-file'] || + argv.s || + argv.schemas || + argv['api-names'], + ); + const explicitConfigPath = (argv.config || argv.c) as string | undefined; + const configPath = + explicitConfigPath || (!hasSourceFlags ? findConfigFile() : undefined); const targetName = (argv.target || argv.t) as string | undefined; - // If config file exists, load and run + let fileConfig: GraphQLSDKConfigTarget = {}; + if (configPath) { const loaded = await loadConfigFile(configPath); if (!loaded.success) { @@ -70,24 +88,36 @@ export const commands = async ( } const config = loaded.config as Record; - - // Check if it's a multi-target config (no source fields at top level) - const isMulti = !('endpoint' in config || 'schemaFile' in config || 'db' in config); + const isMulti = !( + 'endpoint' in config || + 'schemaFile' in config || + 'db' in config + ); if (isMulti) { - // Multi-target: simple for loop over targets const targets = config as Record; const names = targetName ? [targetName] : Object.keys(targets); if (targetName && !targets[targetName]) { - console.error('x', `Target "${targetName}" not found. Available: ${Object.keys(targets).join(', ')}`); + console.error( + 'x', + `Target "${targetName}" not found. Available: ${Object.keys(targets).join(', ')}`, + ); process.exit(1); } + const cliOptions = buildDbConfig( + normalizeCodegenListOptions( + camelizeArgv(argv as Record), + ), + ); let hasError = false; for (const name of names) { console.log(`\n[${name}]`); - const result = await generate(targets[name]); + const result = await generate({ + ...targets[name], + ...cliOptions, + } as GraphQLSDKConfigTarget); printResult(result); if (!result.success) hasError = true; } @@ -97,39 +127,15 @@ export const commands = async ( return argv; } - // Single config - const result = await generate(config as GraphQLSDKConfigTarget); - printResult(result); - if (!result.success) process.exit(1); - prompter.close(); - return argv; + fileConfig = config as GraphQLSDKConfigTarget; } - // No config file - prompt for options using shared questions - const answers = await prompter.prompt(argv as CodegenAnswers, codegenQuestions); - - // Convert kebab-case CLI args to camelCase for internal use - const camelized = camelizeArgv(answers) as CodegenAnswers; - - // Build db config if schemas or apiNames provided - const db = (camelized.schemas || camelized.apiNames) ? { - schemas: camelized.schemas, - apiNames: camelized.apiNames, - } : undefined; - - const result = await generate({ - endpoint: camelized.endpoint, - schemaFile: camelized.schemaFile, - db, - output: camelized.output, - authorization: camelized.authorization, - reactQuery: camelized.reactQuery, - orm: camelized.orm, - browserCompatible: camelized.browserCompatible, - dryRun: camelized.dryRun, - verbose: camelized.verbose, - }); - + const seeded = seedArgvFromConfig(argv, fileConfig); + const answers = hasResolvedCodegenSource(seeded) + ? seeded + : await prompter.prompt(seeded, codegenQuestions); + const options = buildGenerateOptions(answers, fileConfig); + const result = await generate(options); printResult(result); prompter.close(); return argv; @@ -147,13 +153,18 @@ export const options: Partial = { a: 'authorization', v: 'verbose', }, - boolean: [ - 'help', 'version', 'verbose', 'dry-run', 'react-query', 'orm', 'keep-db', 'browser-compatible', - ], string: [ - 'config', 'endpoint', 'schema-file', 'output', 'target', 'authorization', - 'pgpm-module-path', 'pgpm-workspace-path', 'pgpm-module-name', - 'schemas', 'api-names', + 'config', + 'endpoint', + 'schema-file', + 'output', + 'target', + 'authorization', + 'pgpm-module-path', + 'pgpm-workspace-path', + 'pgpm-module-name', + 'schemas', + 'api-names', ], }, }; diff --git a/graphql/codegen/src/cli/shared.ts b/graphql/codegen/src/cli/shared.ts index f147b9fa8..9b08cb8f5 100644 --- a/graphql/codegen/src/cli/shared.ts +++ b/graphql/codegen/src/cli/shared.ts @@ -1,26 +1,45 @@ /** * Shared CLI utilities for graphql-codegen - * - * These are exported so that packages/cli can use the same questions - * and types, ensuring consistency between the two CLIs. + * + * These are exported so that packages/cli can use the same questions, + * types, and transform utilities, ensuring consistency between the two CLIs. */ -import type { Question } from 'inquirerer'; -import type { GenerateResult } from '../core/generate'; import { camelize } from 'inflekt'; import { inflektTree } from 'inflekt/transform-keys'; +import type { Question } from 'inquirerer'; -/** - * Sanitize function that splits comma-separated strings into arrays - */ -export const splitCommas = (input: string | undefined): string[] | undefined => { +import type { GenerateResult } from '../core/generate'; +import type { GraphQLSDKConfigTarget } from '../types/config'; + +export const splitCommas = ( + input: string | undefined, +): string[] | undefined => { if (!input) return undefined; - return input.split(',').map((s) => s.trim()).filter(Boolean); + return input + .split(',') + .map((s) => s.trim()) + .filter(Boolean); }; -/** - * Interface for codegen CLI answers - * CLI accepts kebab-case arguments, converted to camelCase for internal use - */ +function normalizeListOption( + input: unknown, +): string[] | undefined { + if (Array.isArray(input)) { + return input + .flatMap((item) => + typeof item === 'string' ? (splitCommas(item) ?? []) : [String(item)], + ) + .map((s) => s.trim()) + .filter(Boolean); + } + + if (typeof input === 'string') { + return splitCommas(input); + } + + return undefined; +} + export interface CodegenAnswers { endpoint?: string; schemaFile?: string; @@ -29,15 +48,11 @@ export interface CodegenAnswers { apiNames?: string[]; reactQuery?: boolean; orm?: boolean; - browserCompatible?: boolean; authorization?: string; dryRun?: boolean; verbose?: boolean; } -/** - * Questions for the codegen CLI - */ export const codegenQuestions: Question[] = [ { name: 'endpoint', @@ -89,14 +104,6 @@ export const codegenQuestions: Question[] = [ default: false, useDefault: true, }, - { - name: 'browser-compatible', - message: 'Generate browser-compatible code?', - type: 'confirm', - required: false, - default: true, - useDefault: true, - }, { name: 'authorization', message: 'Authorization header value', @@ -121,9 +128,6 @@ export const codegenQuestions: Question[] = [ }, ]; -/** - * Print the result of a generate operation - */ export function printResult(result: GenerateResult): void { if (result.success) { console.log('[ok]', result.message); @@ -137,15 +141,123 @@ export function printResult(result: GenerateResult): void { } } +// ============================================================================ +// Key transform utilities +// ============================================================================ + const isTopLevel = (_key: string, path: string[]) => path.length === 0; -export const camelizeArgv = (argv: Record) => - inflektTree(argv, (key) => { - // inflection.camelize expects underscores, so replace hyphens first - const underscored = key.replace(/-/g, '_'); - return camelize(underscored, true); - }, { - skip: (key, path) => - !isTopLevel(key, path) || - key === '_' || - key.startsWith('_') - }); +const skipNonTopLevel = (key: string, path: string[]) => + !isTopLevel(key, path) || key === '_' || key.startsWith('_'); + +export const camelizeArgv = (argv: Record): Record => + inflektTree( + argv, + (key) => { + const underscored = key.replace(/-/g, '_'); + return camelize(underscored, true); + }, + { skip: skipNonTopLevel }, + ); + +export const hyphenateKeys = (obj: Record): Record => + inflektTree( + obj, + (key) => key.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase()), + { + skip: skipNonTopLevel, + }, + ); + +// ============================================================================ +// Config <-> CLI shape transforms +// ============================================================================ + +export function filterDefined( + obj: Record, +): Record { + return Object.fromEntries( + Object.entries(obj).filter(([, v]) => v !== undefined && v !== null), + ); +} + +export function flattenDbFields( + config: Record, +): Record { + const { db, ...rest } = config; + if (db && typeof db === 'object') { + const dbObj = db as Record; + const schemas = Array.isArray(dbObj.schemas) + ? dbObj.schemas.join(',') + : dbObj.schemas; + const apiNames = Array.isArray(dbObj.apiNames) + ? dbObj.apiNames.join(',') + : dbObj.apiNames; + return { ...rest, schemas, apiNames }; + } + return rest; +} + +export function buildDbConfig( + options: Record, +): Record { + const { schemas, apiNames, ...rest } = options; + if (schemas || apiNames) { + return { ...rest, db: { schemas, apiNames } }; + } + return rest; +} + +/** + * Normalizes top-level list-like CLI options to string arrays. + * This keeps non-interactive paths equivalent to prompt sanitize behavior. + */ +export function normalizeCodegenListOptions( + options: Record, +): Record { + return { + ...options, + schemas: normalizeListOption(options.schemas), + apiNames: normalizeListOption(options.apiNames), + }; +} + +/** + * Returns true when source options are already available, so prompting can be skipped. + */ +export function hasResolvedCodegenSource( + options: Record, +): boolean { + const normalized = normalizeCodegenListOptions(camelizeArgv(options)); + const db = normalized.db as Record | undefined; + const dbSchemas = normalizeListOption(db?.schemas); + const dbApiNames = normalizeListOption(db?.apiNames); + + return Boolean( + normalized.endpoint || + normalized.schemaFile || + (normalized.schemas as string[] | undefined)?.length || + (normalized.apiNames as string[] | undefined)?.length || + dbSchemas?.length || + dbApiNames?.length, + ); +} + +export function seedArgvFromConfig( + argv: Record, + fileConfig: GraphQLSDKConfigTarget, +): Record { + const flat = flattenDbFields(fileConfig as Record); + const hyphenated = hyphenateKeys(flat); + const defined = filterDefined(hyphenated); + return { ...defined, ...argv }; +} + +export function buildGenerateOptions( + answers: Record, + fileConfig: GraphQLSDKConfigTarget = {}, +): GraphQLSDKConfigTarget { + const camelized = camelizeArgv(answers); + const normalized = normalizeCodegenListOptions(camelized); + const withDb = buildDbConfig(normalized); + return { ...fileConfig, ...withDb } as GraphQLSDKConfigTarget; +} diff --git a/graphql/codegen/src/client/error.ts b/graphql/codegen/src/client/error.ts index d879712de..53df412c9 100644 --- a/graphql/codegen/src/client/error.ts +++ b/graphql/codegen/src/client/error.ts @@ -73,7 +73,11 @@ export class DataError extends Error { public readonly fieldName?: string; public readonly constraint?: string; - constructor(type: DataErrorType, message: string, options: DataErrorOptions = {}) { + constructor( + type: DataErrorType, + message: string, + options: DataErrorOptions = {}, + ) { super(message); this.name = 'DataError'; this.type = type; @@ -157,10 +161,14 @@ export const PG_ERROR_CODES = { export const createError = { network: (originalError?: Error) => - new DataError(DataErrorType.NETWORK_ERROR, 'Network error occurred', { originalError }), + new DataError(DataErrorType.NETWORK_ERROR, 'Network error occurred', { + originalError, + }), timeout: (originalError?: Error) => - new DataError(DataErrorType.TIMEOUT_ERROR, 'Request timed out', { originalError }), + new DataError(DataErrorType.TIMEOUT_ERROR, 'Request timed out', { + originalError, + }), unauthorized: (message = 'Authentication required') => new DataError(DataErrorType.UNAUTHORIZED, message), @@ -178,16 +186,38 @@ export const createError = { new DataError(DataErrorType.GRAPHQL_ERROR, message, { code }), uniqueViolation: (message: string, fieldName?: string, constraint?: string) => - new DataError(DataErrorType.UNIQUE_VIOLATION, message, { fieldName, constraint, code: '23505' }), - - foreignKeyViolation: (message: string, fieldName?: string, constraint?: string) => - new DataError(DataErrorType.FOREIGN_KEY_VIOLATION, message, { fieldName, constraint, code: '23503' }), - - notNullViolation: (message: string, fieldName?: string, constraint?: string) => - new DataError(DataErrorType.NOT_NULL_VIOLATION, message, { fieldName, constraint, code: '23502' }), + new DataError(DataErrorType.UNIQUE_VIOLATION, message, { + fieldName, + constraint, + code: '23505', + }), + + foreignKeyViolation: ( + message: string, + fieldName?: string, + constraint?: string, + ) => + new DataError(DataErrorType.FOREIGN_KEY_VIOLATION, message, { + fieldName, + constraint, + code: '23503', + }), + + notNullViolation: ( + message: string, + fieldName?: string, + constraint?: string, + ) => + new DataError(DataErrorType.NOT_NULL_VIOLATION, message, { + fieldName, + constraint, + code: '23502', + }), unknown: (originalError: Error) => - new DataError(DataErrorType.UNKNOWN_ERROR, originalError.message, { originalError }), + new DataError(DataErrorType.UNKNOWN_ERROR, originalError.message, { + originalError, + }), }; // ============================================================================ @@ -208,28 +238,41 @@ function parseGraphQLErrorCode(code: string | undefined): DataErrorType { // GraphQL standard codes if (normalized === 'UNAUTHENTICATED') return DataErrorType.UNAUTHORIZED; if (normalized === 'FORBIDDEN') return DataErrorType.FORBIDDEN; - if (normalized === 'GRAPHQL_VALIDATION_FAILED') return DataErrorType.QUERY_GENERATION_FAILED; + if (normalized === 'GRAPHQL_VALIDATION_FAILED') + return DataErrorType.QUERY_GENERATION_FAILED; // PostgreSQL SQLSTATE codes - if (code === PG_ERROR_CODES.UNIQUE_VIOLATION) return DataErrorType.UNIQUE_VIOLATION; - if (code === PG_ERROR_CODES.FOREIGN_KEY_VIOLATION) return DataErrorType.FOREIGN_KEY_VIOLATION; - if (code === PG_ERROR_CODES.NOT_NULL_VIOLATION) return DataErrorType.NOT_NULL_VIOLATION; - if (code === PG_ERROR_CODES.CHECK_VIOLATION) return DataErrorType.CHECK_VIOLATION; - if (code === PG_ERROR_CODES.EXCLUSION_VIOLATION) return DataErrorType.EXCLUSION_VIOLATION; + if (code === PG_ERROR_CODES.UNIQUE_VIOLATION) + return DataErrorType.UNIQUE_VIOLATION; + if (code === PG_ERROR_CODES.FOREIGN_KEY_VIOLATION) + return DataErrorType.FOREIGN_KEY_VIOLATION; + if (code === PG_ERROR_CODES.NOT_NULL_VIOLATION) + return DataErrorType.NOT_NULL_VIOLATION; + if (code === PG_ERROR_CODES.CHECK_VIOLATION) + return DataErrorType.CHECK_VIOLATION; + if (code === PG_ERROR_CODES.EXCLUSION_VIOLATION) + return DataErrorType.EXCLUSION_VIOLATION; return DataErrorType.UNKNOWN_ERROR; } function classifyByMessage(message: string): DataErrorType { const lower = message.toLowerCase(); - + if (lower.includes('timeout') || lower.includes('timed out')) { return DataErrorType.TIMEOUT_ERROR; } - if (lower.includes('network') || lower.includes('fetch') || lower.includes('failed to fetch')) { + if ( + lower.includes('network') || + lower.includes('fetch') || + lower.includes('failed to fetch') + ) { return DataErrorType.NETWORK_ERROR; } - if (lower.includes('unauthorized') || lower.includes('authentication required')) { + if ( + lower.includes('unauthorized') || + lower.includes('authentication required') + ) { return DataErrorType.UNAUTHORIZED; } if (lower.includes('forbidden') || lower.includes('permission')) { @@ -241,21 +284,30 @@ function classifyByMessage(message: string): DataErrorType { if (lower.includes('foreign key constraint')) { return DataErrorType.FOREIGN_KEY_VIOLATION; } - if (lower.includes('not-null constraint') || lower.includes('null value in column')) { + if ( + lower.includes('not-null constraint') || + lower.includes('null value in column') + ) { return DataErrorType.NOT_NULL_VIOLATION; } - + return DataErrorType.UNKNOWN_ERROR; } -function extractFieldFromError(message: string, constraint?: string, column?: string): string | undefined { +function extractFieldFromError( + message: string, + constraint?: string, + column?: string, +): string | undefined { if (column) return column; const columnMatch = message.match(/column\s+"?([a-z_][a-z0-9_]*)"?/i); if (columnMatch) return columnMatch[1]; if (constraint) { - const constraintMatch = constraint.match(/_([a-z_][a-z0-9_]*)_(?:key|fkey|check|pkey)$/i); + const constraintMatch = constraint.match( + /_([a-z_][a-z0-9_]*)_(?:key|fkey|check|pkey)$/i, + ); if (constraintMatch) return constraintMatch[1]; } @@ -286,7 +338,11 @@ export function parseGraphQLError(error: unknown): DataError { const column = gqlError.extensions?.column as string | undefined; const constraint = gqlError.extensions?.constraint as string | undefined; - const fieldName = extractFieldFromError(gqlError.message, constraint, column); + const fieldName = extractFieldFromError( + gqlError.message, + constraint, + column, + ); if (mappedType !== DataErrorType.UNKNOWN_ERROR) { return new DataError(mappedType, gqlError.message, { diff --git a/graphql/codegen/src/client/execute.ts b/graphql/codegen/src/client/execute.ts index 6f59e7cec..b8b4e1562 100644 --- a/graphql/codegen/src/client/execute.ts +++ b/graphql/codegen/src/client/execute.ts @@ -5,8 +5,8 @@ import type { DocumentNode } from 'graphql'; import { print } from 'graphql'; +import { createError, type DataError, parseGraphQLError } from './error'; import { TypedDocumentString } from './typed-document'; -import { createError, parseGraphQLError, type DataError } from './error'; // ============================================================================ // Types @@ -17,13 +17,15 @@ type ExecutableDocument = | DocumentNode | string; -type ResultOf = TDocument extends TypedDocumentString - ? TResult - : unknown; +type ResultOf = + TDocument extends TypedDocumentString + ? TResult + : unknown; -type VariablesOf = TDocument extends TypedDocumentString - ? TVariables - : Record; +type VariablesOf = + TDocument extends TypedDocumentString + ? TVariables + : Record; export interface ExecuteOptions { /** Custom headers to include */ @@ -173,7 +175,11 @@ export interface GraphQLClientOptions { * Create a GraphQL client instance */ export function createGraphQLClient(options: GraphQLClientOptions) { - const { endpoint, headers: defaultHeaders = {}, timeout: defaultTimeout = 30000 } = options; + const { + endpoint, + headers: defaultHeaders = {}, + timeout: defaultTimeout = 30000, + } = options; return { /** diff --git a/graphql/codegen/src/client/index.ts b/graphql/codegen/src/client/index.ts index 53b0bb352..c29e97c93 100644 --- a/graphql/codegen/src/client/index.ts +++ b/graphql/codegen/src/client/index.ts @@ -2,24 +2,25 @@ * Client exports */ -export { TypedDocumentString, type DocumentTypeDecoration } from './typed-document'; - export { + createError, DataError, + type DataErrorOptions, DataErrorType, - createError, - parseGraphQLError, + type GraphQLError, isDataError, + parseGraphQLError, PG_ERROR_CODES, - type DataErrorOptions, - type GraphQLError, } from './error'; - export { - execute, createGraphQLClient, + execute, type ExecuteOptions, - type GraphQLClientOptions, type GraphQLClient, + type GraphQLClientOptions, type GraphQLResponse, } from './execute'; +export { + type DocumentTypeDecoration, + TypedDocumentString, +} from './typed-document'; diff --git a/graphql/codegen/src/core/ast.ts b/graphql/codegen/src/core/ast.ts index d7903bd09..d402ccb46 100644 --- a/graphql/codegen/src/core/ast.ts +++ b/graphql/codegen/src/core/ast.ts @@ -9,22 +9,19 @@ import type { } from 'graphql'; import { camelize, singularize } from 'inflekt'; - import { getCustomAst } from './custom-ast'; import type { ASTFunctionParams, - QueryFieldSelection, MutationASTParams, NestedProperties, ObjectArrayItem, + QueryFieldSelection, QueryProperty, } from './types'; const NON_MUTABLE_PROPS = ['createdAt', 'createdBy', 'updatedAt', 'updatedBy']; -const objectToArray = ( - obj: Record -): ObjectArrayItem[] => +const objectToArray = (obj: Record): ObjectArrayItem[] => Object.keys(obj).map((k) => ({ key: k, name: obj[k].name || k, @@ -190,8 +187,7 @@ export const getMany = ({ selection, }: ASTFunctionParams): DocumentNode => { const Singular = query.model; - const Plural = - operationName.charAt(0).toUpperCase() + operationName.slice(1); + const Plural = operationName.charAt(0).toUpperCase() + operationName.slice(1); const Condition = `${Singular}Condition`; const Filter = `${Singular}Filter`; const OrderBy = `${Plural}OrderBy`; @@ -311,7 +307,7 @@ export const getOne = ({ selection, }: ASTFunctionParams): DocumentNode => { const variableDefinitions: VariableDefinitionNode[] = Object.keys( - query.properties + query.properties, ) .map((key) => ({ key, ...query.properties[key] })) .filter((field) => field.isNotNull) @@ -379,10 +375,7 @@ export const createOne = ({ throw new Error(`No input field for mutation: ${mutationName}`); } - const modelName = camelize( - [singularize(mutation.model)].join('_'), - true - ); + const modelName = camelize([singularize(mutation.model)].join('_'), true); const inputProperties = mutation.properties.input .properties as NestedProperties; @@ -393,10 +386,10 @@ export const createOne = ({ } const allAttrs = objectToArray( - modelProperties.properties as Record + modelProperties.properties as Record, ); const attrs = allAttrs.filter( - (field) => !NON_MUTABLE_PROPS.includes(field.name) + (field) => !NON_MUTABLE_PROPS.includes(field.name), ); const variableDefinitions = getCreateVariablesAst(attrs); @@ -413,7 +406,7 @@ export const createOne = ({ t.objectField({ name: field.name, value: t.variable({ name: field.name }), - }) + }), ), }), }), @@ -448,10 +441,7 @@ export const patchOne = ({ throw new Error(`No input field for mutation: ${mutationName}`); } - const modelName = camelize( - [singularize(mutation.model)].join('_'), - true - ); + const modelName = camelize([singularize(mutation.model)].join('_'), true); const inputProperties = mutation.properties.input .properties as NestedProperties; @@ -462,10 +452,10 @@ export const patchOne = ({ : []; const patchAttrs = allAttrs.filter( - (prop) => !NON_MUTABLE_PROPS.includes(prop.name) + (prop) => !NON_MUTABLE_PROPS.includes(prop.name), ); const patchByAttrs = objectToArray( - inputProperties as Record + inputProperties as Record, ).filter((n) => n.name !== 'patch'); const patchers = patchByAttrs.map((p) => p.name); @@ -480,7 +470,7 @@ export const patchOne = ({ t.objectField({ name: field.name, value: t.variable({ name: field.name }), - }) + }), ), t.objectField({ name: 'patch', @@ -491,7 +481,7 @@ export const patchOne = ({ t.objectField({ name: field.name, value: t.variable({ name: field.name }), - }) + }), ), }), }), @@ -525,15 +515,12 @@ export const deleteOne = ({ throw new Error(`No input field for mutation: ${mutationName}`); } - const modelName = camelize( - [singularize(mutation.model)].join('_'), - true - ); + const modelName = camelize([singularize(mutation.model)].join('_'), true); const inputProperties = mutation.properties.input .properties as NestedProperties; const deleteAttrs = objectToArray( - inputProperties as Record + inputProperties as Record, ); const variableDefinitions: VariableDefinitionNode[] = deleteAttrs.map( @@ -550,7 +537,7 @@ export const deleteOne = ({ variable: t.variable({ name: fieldName }), type, }); - } + }, ); const selectArgs: ArgumentNode[] = [ @@ -561,7 +548,7 @@ export const deleteOne = ({ t.objectField({ name: f.name, value: t.variable({ name: f.name }), - }) + }), ), }), }), @@ -582,7 +569,9 @@ export const deleteOne = ({ return ast; }; -export function getSelections(selection: QueryFieldSelection[] = []): FieldNode[] { +export function getSelections( + selection: QueryFieldSelection[] = [], +): FieldNode[] { const selectionAst = (field: string | QueryFieldSelection): FieldNode => { if (typeof field === 'string') { return t.field({ name: field }); @@ -597,7 +586,10 @@ export function getSelections(selection: QueryFieldSelection[] = []): FieldNode[ 'pgType' in fieldDefn.type ) { const customAst = getCustomAst( - fieldDefn as { name: string; type: { gqlType: string; pgType: string; isArray: boolean } } + fieldDefn as { + name: string; + type: { gqlType: string; pgType: string; isArray: boolean }; + }, ); if (customAst) return customAst; } @@ -618,7 +610,7 @@ export function getSelections(selection: QueryFieldSelection[] = []): FieldNode[ }); return argAst ? [...acc, argAst] : acc; }, - [] + [], ); const subSelections = @@ -682,7 +674,7 @@ function getComplexValueAst(value: unknown): ValueNode { t.objectField({ name: key, value: getComplexValueAst(val), - }) + }), ), }); } @@ -691,7 +683,7 @@ function getComplexValueAst(value: unknown): ValueNode { } function getCreateVariablesAst( - attrs: ObjectArrayItem[] + attrs: ObjectArrayItem[], ): VariableDefinitionNode[] { return attrs.map((field) => { const { @@ -716,13 +708,17 @@ function getCreateVariablesAst( function getUpdateVariablesAst( attrs: ObjectArrayItem[], - patchers: string[] + patchers: string[], ): VariableDefinitionNode[] { const patchVariables: VariableDefinitionNode[] = attrs .filter((field) => !patchers.includes(field.name)) .map((field) => { - const { name: fieldName, type: fieldType, isArray, isArrayNotNull } = - field; + const { + name: fieldName, + type: fieldType, + isArray, + isArrayNotNull, + } = field; let type: TypeNode = t.namedType({ type: fieldType }); if (isArray) { type = t.listType({ type }); diff --git a/graphql/codegen/src/core/codegen/babel-ast.ts b/graphql/codegen/src/core/codegen/babel-ast.ts index 9a189b2f7..40caa2e76 100644 --- a/graphql/codegen/src/core/codegen/babel-ast.ts +++ b/graphql/codegen/src/core/codegen/babel-ast.ts @@ -9,7 +9,7 @@ import generate from '@babel/generator'; import * as t from '@babel/types'; // Re-export for convenience -export { t, generate }; +export { generate, t }; /** * Generate code from an array of statements @@ -50,10 +50,11 @@ export const commentLine = (value: string): t.CommentLine => { * Add a leading JSDoc comment to a node */ export function addJSDocComment(node: T, lines: string[]): T { - const commentText = lines.length === 1 - ? `* ${lines[0]} ` - : `*\n${lines.map(line => ` * ${line}`).join('\n')}\n `; - + const commentText = + lines.length === 1 + ? `* ${lines[0]} ` + : `*\n${lines.map((line) => ` * ${line}`).join('\n')}\n `; + if (!node.leadingComments) { node.leadingComments = []; } @@ -76,16 +77,15 @@ export function addLineComment(node: T, text: string): T { * Create an 'as const' assertion - common pattern worth abstracting */ export function asConst(expression: t.Expression): t.TSAsExpression { - return t.tsAsExpression( - expression, - t.tsTypeReference(t.identifier('const')) - ); + return t.tsAsExpression(expression, t.tsTypeReference(t.identifier('const'))); } /** * Create an array expression with 'as const' - very common pattern */ -export function constArray(elements: (t.Expression | t.SpreadElement)[]): t.TSAsExpression { +export function constArray( + elements: (t.Expression | t.SpreadElement)[], +): t.TSAsExpression { return asConst(t.arrayExpression(elements)); } @@ -95,7 +95,7 @@ export function constArray(elements: (t.Expression | t.SpreadElement)[]): t.TSAs export function typedParam( name: string, typeAnnotation: t.TSType, - optional: boolean = false + optional: boolean = false, ): t.Identifier { const param = t.identifier(name); param.typeAnnotation = t.tsTypeAnnotation(typeAnnotation); @@ -125,7 +125,7 @@ export function keyofTypeof(name: string): t.TSTypeOperator { export function createTypedCallExpression( callee: t.Expression, args: (t.Expression | t.SpreadElement)[], - typeParams: t.TSType[] + typeParams: t.TSType[], ): t.CallExpression { const call = t.callExpression(callee, args); if (typeParams.length > 0) { diff --git a/graphql/codegen/src/core/codegen/barrel.ts b/graphql/codegen/src/core/codegen/barrel.ts index 25d5a6fa6..64032e99c 100644 --- a/graphql/codegen/src/core/codegen/barrel.ts +++ b/graphql/codegen/src/core/codegen/barrel.ts @@ -3,18 +3,19 @@ * * Using Babel AST for generating barrel (index.ts) files with re-exports. */ -import type { CleanTable } from '../../types/schema'; import * as t from '@babel/types'; -import { generateCode, addJSDocComment } from './babel-ast'; + +import type { CleanTable } from '../../types/schema'; +import { addJSDocComment, generateCode } from './babel-ast'; +import { getOperationHookName } from './type-resolver'; import { + getCreateMutationHookName, + getDeleteMutationHookName, getListQueryHookName, getSingleQueryHookName, - getCreateMutationHookName, getUpdateMutationHookName, - getDeleteMutationHookName, hasValidPrimaryKey, } from './utils'; -import { getOperationHookName } from './type-resolver'; /** * Helper to create export * from './module' statement @@ -62,16 +63,16 @@ export function generateMutationsBarrel(tables: CleanTable[]): string { // Export all mutation hooks for (const table of tables) { const createHookName = getCreateMutationHookName(table); - const updateHookName = getUpdateMutationHookName(table); - const deleteHookName = getDeleteMutationHookName(table); statements.push(exportAllFrom(`./${createHookName}`)); - // Only add update/delete if they exist - if (table.query?.update !== null) { + // Only add update/delete if they exist AND table has valid PK + if (table.query?.update !== null && hasValidPrimaryKey(table)) { + const updateHookName = getUpdateMutationHookName(table); statements.push(exportAllFrom(`./${updateHookName}`)); } - if (table.query?.delete !== null) { + if (table.query?.delete !== null && hasValidPrimaryKey(table)) { + const deleteHookName = getDeleteMutationHookName(table); statements.push(exportAllFrom(`./${deleteHookName}`)); } } @@ -95,7 +96,6 @@ export function generateMutationsBarrel(tables: CleanTable[]): string { * @param hasSchemaTypes - Whether schema-types.ts was generated */ export interface MainBarrelOptions { - hasSchemaTypes?: boolean; hasMutations?: boolean; /** Whether query-keys.ts was generated */ hasQueryKeys?: boolean; @@ -107,12 +107,11 @@ export interface MainBarrelOptions { export function generateMainBarrel( tables: CleanTable[], - options: MainBarrelOptions = {} + options: MainBarrelOptions = {}, ): string { const opts: MainBarrelOptions = options; const { - hasSchemaTypes = false, hasMutations = true, hasQueryKeys = false, hasMutationKeys = false, @@ -122,17 +121,9 @@ export function generateMainBarrel( const statements: t.Statement[] = []; - // Client configuration + // Client configuration (ORM wrapper with configure/getClient) statements.push(exportAllFrom('./client')); - // Entity and filter types - statements.push(exportAllFrom('./types')); - - // Schema types (input, payload, enum types) - if (hasSchemaTypes) { - statements.push(exportAllFrom('./schema-types')); - } - // Centralized query keys (for cache management) if (hasQueryKeys) { statements.push(exportAllFrom('./query-keys')); @@ -181,8 +172,12 @@ export function generateMainBarrel( "import { useCarsQuery, useCreateCarMutation } from './generated';", '', 'function MyComponent() {', - ' const { data, isLoading } = useCarsQuery({ first: 10 });', - ' const { mutate } = useCreateCarMutation();', + ' const { data, isLoading } = useCarsQuery({', + ' selection: { fields: { id: true }, first: 10 },', + ' });', + ' const { mutate } = useCreateCarMutation({', + ' selection: { fields: { id: true } },', + ' });', ' // ...', '}', '```', @@ -240,7 +235,7 @@ export function generateRootBarrel(options: RootBarrelOptions = {}): string { */ export function generateCustomQueriesBarrel( tables: CleanTable[], - customQueryNames: string[] + customQueryNames: string[], ): string { const statements: t.Statement[] = []; const exportedHooks = new Set(); @@ -289,7 +284,7 @@ export function generateCustomQueriesBarrel( */ export function generateCustomMutationsBarrel( tables: CleanTable[], - customMutationNames: string[] + customMutationNames: string[], ): string { const statements: t.Statement[] = []; const exportedHooks = new Set(); @@ -302,15 +297,15 @@ export function generateCustomMutationsBarrel( exportedHooks.add(createHookName); } - // Only add update/delete if they exist - if (table.query?.update !== null) { + // Only add update/delete if they exist AND table has valid PK + if (table.query?.update !== null && hasValidPrimaryKey(table)) { const updateHookName = getUpdateMutationHookName(table); if (!exportedHooks.has(updateHookName)) { statements.push(exportAllFrom(`./${updateHookName}`)); exportedHooks.add(updateHookName); } } - if (table.query?.delete !== null) { + if (table.query?.delete !== null && hasValidPrimaryKey(table)) { const deleteHookName = getDeleteMutationHookName(table); if (!exportedHooks.has(deleteHookName)) { statements.push(exportAllFrom(`./${deleteHookName}`)); diff --git a/graphql/codegen/src/core/codegen/client.ts b/graphql/codegen/src/core/codegen/client.ts index 809c6f513..047517f6e 100644 --- a/graphql/codegen/src/core/codegen/client.ts +++ b/graphql/codegen/src/core/codegen/client.ts @@ -1,74 +1,42 @@ /** - * Client generator - generates client.ts with configure() and execute() + * Client generator - generates client.ts as ORM client wrapper * - * Reads from template files in the templates/ directory for proper type checking. + * Uses template-copy pattern: reads hooks-client.ts from templates/ + * and writes it to the output directory with a generated file header. */ import * as fs from 'fs'; import * as path from 'path'; -import { getGeneratedFileHeader } from './utils'; -export interface GenerateClientFileOptions { - /** - * Generate browser-compatible code using native fetch - * When true (default), uses native W3C fetch API - * When false, uses undici fetch with dispatcher support for localhost DNS resolution - * @default true - */ - browserCompatible?: boolean; -} +import { getGeneratedFileHeader } from './utils'; -/** - * Find a template file path. - * Templates are at ./templates/ relative to this file in both src/ and dist/. - */ function findTemplateFile(templateName: string): string { const templatePath = path.join(__dirname, 'templates', templateName); - if (fs.existsSync(templatePath)) { return templatePath; } - throw new Error( - `Could not find template file: ${templateName}. ` + - `Searched in: ${templatePath}` + `Could not find template file: ${templateName}. Searched in: ${templatePath}`, ); } -/** - * Read a template file and replace the header with generated file header - */ function readTemplateFile(templateName: string, description: string): string { const templatePath = findTemplateFile(templateName); let content = fs.readFileSync(templatePath, 'utf-8'); - - // Replace the source file header comment with the generated file header - // Match the header pattern used in template files const headerPattern = /\/\*\*[\s\S]*?\* NOTE: This file is read at codegen time and written to output\.[\s\S]*?\*\/\n*/; - content = content.replace( headerPattern, - getGeneratedFileHeader(description) + '\n' + getGeneratedFileHeader(description) + '\n', ); - return content; } /** - * Generate client.ts content - * @param options - Generation options + * Generate client.ts content - ORM client wrapper with configure/getClient */ -export function generateClientFile( - options: GenerateClientFileOptions = {} -): string { - const { browserCompatible = true } = options; - - const templateName = browserCompatible - ? 'client.browser.ts' - : 'client.node.ts'; - +export function generateClientFile(): string { return readTemplateFile( - templateName, - 'GraphQL client configuration and execution' + 'hooks-client.ts', + 'ORM client wrapper for React Query hooks', ); } diff --git a/graphql/codegen/src/core/codegen/custom-mutations.ts b/graphql/codegen/src/core/codegen/custom-mutations.ts index 2d9a10aef..ebd589bf3 100644 --- a/graphql/codegen/src/core/codegen/custom-mutations.ts +++ b/graphql/codegen/src/core/codegen/custom-mutations.ts @@ -1,35 +1,55 @@ /** - * Custom mutation hook generators for non-table operations + * Custom mutation hook generators for non-table operations (Babel AST-based) * * Generates hooks for operations discovered via schema introspection * that are NOT table CRUD operations (e.g., login, register, etc.) * + * Delegates to ORM custom mutation operations: + * getClient().mutation.operationName(args, { select }).unwrap() + * * Output structure: * mutations/ * useLoginMutation.ts * useRegisterMutation.ts * ... */ -import type { - CleanOperation, - CleanArgument, - TypeRegistry, -} from '../../types/schema'; import * as t from '@babel/types'; -import { generateCode, addJSDocComment, typedParam, createTypedCallExpression } from './babel-ast'; -import { buildCustomMutationString } from './schema-gql-ast'; + +import type { CleanOperation, TypeRegistry } from '../../types/schema'; +import { + buildSelectionArgsCall, + callExpr, + constDecl, + createFunctionParam, + createImportDeclaration, + createSTypeParam, + createTypeReExport, + customSelectResultTypeLiteral, + destructureParamsWithSelection, + exportDeclareFunction, + exportFunction, + generateHookFileCode, + getClientCustomCallUnwrap, + objectProp, + omitType, + returnUseMutation, + selectionConfigType, + spreadObj, + sRef, + typeRef, + useMutationOptionsType, + useMutationResultType, + voidStatement, +} from './hooks-ast'; +import { getSelectTypeName } from './select-helpers'; import { - typeRefToTsType, - isTypeRequired, - getOperationHookName, - getOperationFileName, - getOperationVariablesTypeName, - getOperationResultTypeName, - getDocumentConstName, createTypeTracker, - type TypeTracker, + getOperationFileName, + getOperationHookName, + getTypeBaseName, + typeRefToTsType, } from './type-resolver'; -import { getGeneratedFileHeader } from './utils'; +import { ucFirst } from './utils'; export interface GeneratedCustomMutationFile { fileName: string; @@ -40,34 +60,14 @@ export interface GeneratedCustomMutationFile { export interface GenerateCustomMutationHookOptions { operation: CleanOperation; typeRegistry: TypeRegistry; - maxDepth?: number; skipQueryField?: boolean; reactQueryEnabled?: boolean; tableTypeNames?: Set; useCentralizedKeys?: boolean; } -interface VariablesProp { - name: string; - type: string; - optional: boolean; - docs?: string[]; -} - -function generateVariablesProperties( - args: CleanArgument[], - tracker?: TypeTracker -): VariablesProp[] { - return args.map((arg) => ({ - name: arg.name, - type: typeRefToTsType(arg.type, tracker), - optional: !isTypeRequired(arg.type), - docs: arg.description ? [arg.description] : undefined, - })); -} - export function generateCustomMutationHook( - options: GenerateCustomMutationHookOptions + options: GenerateCustomMutationHookOptions, ): GeneratedCustomMutationFile | null { const { operation, reactQueryEnabled = true } = options; @@ -79,216 +79,322 @@ export function generateCustomMutationHook( return generateCustomMutationHookInternal(options); } catch (err) { console.error(`Error generating hook for mutation: ${operation.name}`); - console.error(` Args: ${operation.args.length}, Return type: ${operation.returnType.kind}/${operation.returnType.name}`); + console.error( + ` Args: ${operation.args.length}, Return type: ${operation.returnType.kind}/${operation.returnType.name}`, + ); throw err; } } function generateCustomMutationHookInternal( - options: GenerateCustomMutationHookOptions + options: GenerateCustomMutationHookOptions, ): GeneratedCustomMutationFile { const { operation, typeRegistry, - maxDepth = 2, - skipQueryField = true, tableTypeNames, useCentralizedKeys = true, } = options; const hookName = getOperationHookName(operation.name, 'mutation'); const fileName = getOperationFileName(operation.name, 'mutation'); - const variablesTypeName = getOperationVariablesTypeName(operation.name, 'mutation'); - const resultTypeName = getOperationResultTypeName(operation.name, 'mutation'); - const documentConstName = getDocumentConstName(operation.name, 'mutation'); + const varTypeName = `${ucFirst(operation.name)}Variables`; const tracker = createTypeTracker({ tableTypeNames }); - const mutationDocument = buildCustomMutationString({ - operation, - typeRegistry, - maxDepth, - skipQueryField, - }); - - const statements: t.Statement[] = []; + const hasArgs = operation.args.length > 0; - const variablesProps = - operation.args.length > 0 - ? generateVariablesProperties(operation.args, tracker) - : []; + typeRefToTsType(operation.returnType, tracker); + for (const arg of operation.args) { + typeRefToTsType(arg.type, tracker); + } - const resultType = typeRefToTsType(operation.returnType, tracker); + const selectTypeName = getSelectTypeName(operation.returnType); + const payloadTypeName = getTypeBaseName(operation.returnType); + const hasSelect = !!selectTypeName && !!payloadTypeName; - const schemaTypes = tracker.getImportableTypes(); - const tableTypes = tracker.getTableTypes(); + const statements: t.Statement[] = []; - const reactQueryImport = t.importDeclaration( - [t.importSpecifier(t.identifier('useMutation'), t.identifier('useMutation'))], - t.stringLiteral('@tanstack/react-query') + // Imports + statements.push( + createImportDeclaration('@tanstack/react-query', ['useMutation']), ); - statements.push(reactQueryImport); - - const reactQueryTypeImport = t.importDeclaration( - [t.importSpecifier(t.identifier('UseMutationOptions'), t.identifier('UseMutationOptions'))], - t.stringLiteral('@tanstack/react-query') + statements.push( + createImportDeclaration( + '@tanstack/react-query', + ['UseMutationOptions', 'UseMutationResult'], + true, + ), ); - reactQueryTypeImport.importKind = 'type'; - statements.push(reactQueryTypeImport); - - const clientImport = t.importDeclaration( - [t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], - t.stringLiteral('../client') + statements.push(createImportDeclaration('../client', ['getClient'])); + statements.push( + createImportDeclaration('../selection', ['buildSelectionArgs']), + ); + statements.push( + createImportDeclaration('../selection', ['SelectionConfig'], true), ); - statements.push(clientImport); - if (tableTypes.length > 0) { - const typesImport = t.importDeclaration( - tableTypes.map((tt) => t.importSpecifier(t.identifier(tt), t.identifier(tt))), - t.stringLiteral('../types') + if (useCentralizedKeys) { + statements.push( + createImportDeclaration('../mutation-keys', ['customMutationKeys']), ); - typesImport.importKind = 'type'; - statements.push(typesImport); } - if (schemaTypes.length > 0) { - const schemaTypesImport = t.importDeclaration( - schemaTypes.map((st) => t.importSpecifier(t.identifier(st), t.identifier(st))), - t.stringLiteral('../schema-types') + if (hasArgs) { + statements.push( + createImportDeclaration('../../orm/mutation', [varTypeName], true), ); - schemaTypesImport.importKind = 'type'; - statements.push(schemaTypesImport); } - if (useCentralizedKeys) { - const mutationKeyImport = t.importDeclaration( - [t.importSpecifier(t.identifier('customMutationKeys'), t.identifier('customMutationKeys'))], - t.stringLiteral('../mutation-keys') + const inputTypeImports: string[] = []; + if (hasSelect) { + inputTypeImports.push(selectTypeName!); + inputTypeImports.push(payloadTypeName!); + } else { + for (const refType of tracker.referencedTypes) { + if (!inputTypeImports.includes(refType)) { + inputTypeImports.push(refType); + } + } + } + if (inputTypeImports.length > 0) { + statements.push( + createImportDeclaration('../../orm/input-types', inputTypeImports, true), ); - statements.push(mutationKeyImport); } - const mutationDocConst = t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier(documentConstName), - t.templateLiteral( - [t.templateElement({ raw: '\n' + mutationDocument, cooked: '\n' + mutationDocument }, true)], - [] - ) - ), - ]); - const mutationDocExport = t.exportNamedDeclaration(mutationDocConst); - addJSDocComment(mutationDocExport, ['GraphQL mutation document']); - statements.push(mutationDocExport); - - if (operation.args.length > 0) { - const variablesInterfaceProps = variablesProps.map((vp) => { - const prop = t.tsPropertySignature( - t.identifier(vp.name), - t.tsTypeAnnotation(t.tsTypeReference(t.identifier(vp.type))) - ); - prop.optional = vp.optional; - return prop; - }); - const variablesInterface = t.tsInterfaceDeclaration( - t.identifier(variablesTypeName), - null, - null, - t.tsInterfaceBody(variablesInterfaceProps) + if (hasSelect) { + statements.push( + createImportDeclaration( + '../../orm/select-types', + ['InferSelectResult', 'StrictSelect'], + true, + ), ); - statements.push(t.exportNamedDeclaration(variablesInterface)); } - const resultInterfaceBody = t.tsInterfaceBody([ - t.tsPropertySignature( - t.identifier(operation.name), - t.tsTypeAnnotation(t.tsTypeReference(t.identifier(resultType))) - ), - ]); - const resultInterface = t.tsInterfaceDeclaration( - t.identifier(resultTypeName), - null, - null, - resultInterfaceBody - ); - statements.push(t.exportNamedDeclaration(resultInterface)); + // Re-exports + if (hasArgs) { + statements.push(createTypeReExport([varTypeName], '../../orm/mutation')); + } + if (hasSelect) { + statements.push( + createTypeReExport([selectTypeName!], '../../orm/input-types'), + ); + } - const hasArgs = operation.args.length > 0; + // Hook + if (hasSelect) { + const mutationVarType: t.TSType = hasArgs + ? typeRef(varTypeName) + : t.tsVoidKeyword(); + + const selectedResultType = (sel: t.TSType) => + customSelectResultTypeLiteral( + operation.name, + operation.returnType, + payloadTypeName!, + sel, + ); - const hookBodyStatements: t.Statement[] = []; - const mutationOptions: (t.ObjectProperty | t.SpreadElement)[] = []; + // Overload 1: with selection.fields + const o1ParamType = t.tsIntersectionType([ + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation( + t.tsParenthesizedType( + t.tsIntersectionType([ + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier('fields'), + t.tsTypeAnnotation(sRef()), + ), + ]), + typeRef('StrictSelect', [sRef(), typeRef(selectTypeName!)]), + ]), + ), + ), + ), + ]), + useMutationOptionsType(selectedResultType(sRef()), mutationVarType), + ]); + statements.push( + exportDeclareFunction( + hookName, + createSTypeParam(selectTypeName!), + [createFunctionParam('params', o1ParamType)], + useMutationResultType(selectedResultType(sRef()), mutationVarType), + ), + ); - if (useCentralizedKeys) { - mutationOptions.push( - t.objectProperty( - t.identifier('mutationKey'), - t.callExpression( - t.memberExpression(t.identifier('customMutationKeys'), t.identifier(operation.name)), - [] + // Implementation + const implSelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName!))), + ); + const implParamType = t.tsIntersectionType([ + t.tsTypeLiteral([implSelProp]), + omitType( + typeRef('UseMutationOptions', [ + t.tsAnyKeyword(), + typeRef('Error'), + mutationVarType, + ]), + ['mutationFn'], + ), + ]); + + const body: t.Statement[] = []; + body.push(buildSelectionArgsCall(selectTypeName!)); + body.push(destructureParamsWithSelection('mutationOptions')); + body.push(voidStatement('_selection')); + + const mutationKeyExpr = useCentralizedKeys + ? callExpr( + t.memberExpression( + t.identifier('customMutationKeys'), + t.identifier(operation.name), + ), + [], ) - ) + : undefined; + + const selectArgExpr = t.objectExpression([ + objectProp( + 'select', + t.memberExpression(t.identifier('args'), t.identifier('select')), + ), + ]); + + let mutationFnExpr: t.Expression; + if (hasArgs) { + const variablesParam = createFunctionParam( + 'variables', + typeRef(varTypeName), + ); + mutationFnExpr = t.arrowFunctionExpression( + [variablesParam], + getClientCustomCallUnwrap( + 'mutation', + operation.name, + [t.identifier('variables')], + selectArgExpr, + ), + ); + } else { + mutationFnExpr = t.arrowFunctionExpression( + [], + getClientCustomCallUnwrap( + 'mutation', + operation.name, + [], + selectArgExpr, + ), + ); + } + + body.push( + returnUseMutation( + mutationFnExpr, + [spreadObj(t.identifier('mutationOptions'))], + mutationKeyExpr, + ), ); - } - if (hasArgs) { - mutationOptions.push( - t.objectProperty( - t.identifier('mutationFn'), - t.arrowFunctionExpression( - [typedParam('variables', t.tsTypeReference(t.identifier(variablesTypeName)))], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(documentConstName), t.identifier('variables')], - [ - t.tsTypeReference(t.identifier(resultTypeName)), - t.tsTypeReference(t.identifier(variablesTypeName)), - ] - ) - ) - ) + statements.push( + exportFunction( + hookName, + null, + [createFunctionParam('params', implParamType)], + body, + ), ); } else { - mutationOptions.push( - t.objectProperty( - t.identifier('mutationFn'), - t.arrowFunctionExpression( - [], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(documentConstName)], - [t.tsTypeReference(t.identifier(resultTypeName))] - ) - ) - ) + // Without select: simple hook (scalar return type) + const resultTypeStr = typeRefToTsType(operation.returnType, tracker); + const resultTypeLiteral = t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier(operation.name), + t.tsTypeAnnotation(typeRef(resultTypeStr)), + ), + ]); + const mutationVarType: t.TSType = hasArgs + ? typeRef(varTypeName) + : t.tsVoidKeyword(); + + const optionsType = omitType( + typeRef('UseMutationOptions', [ + resultTypeLiteral, + typeRef('Error'), + mutationVarType, + ]), + ['mutationFn'], ); - } - mutationOptions.push(t.spreadElement(t.identifier('options'))); + const body: t.Statement[] = []; + body.push( + constDecl( + 'mutationOptions', + t.logicalExpression( + '??', + t.identifier('params'), + t.objectExpression([]), + ), + ), + ); - hookBodyStatements.push( - t.returnStatement( - t.callExpression(t.identifier('useMutation'), [t.objectExpression(mutationOptions)]) - ) - ); + const mutationKeyExpr = useCentralizedKeys + ? callExpr( + t.memberExpression( + t.identifier('customMutationKeys'), + t.identifier(operation.name), + ), + [], + ) + : undefined; - const optionsType = hasArgs - ? `Omit, 'mutationFn'>` - : `Omit, 'mutationFn'>`; + let mutationFnExpr: t.Expression; + if (hasArgs) { + const variablesParam = createFunctionParam( + 'variables', + typeRef(varTypeName), + ); + mutationFnExpr = t.arrowFunctionExpression( + [variablesParam], + getClientCustomCallUnwrap('mutation', operation.name, [ + t.identifier('variables'), + ]), + ); + } else { + mutationFnExpr = t.arrowFunctionExpression( + [], + getClientCustomCallUnwrap('mutation', operation.name, []), + ); + } + + body.push( + returnUseMutation( + mutationFnExpr, + [spreadObj(t.identifier('mutationOptions'))], + mutationKeyExpr, + ), + ); - const optionsParam = t.identifier('options'); - optionsParam.optional = true; - optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(optionsType))); + statements.push( + exportFunction( + hookName, + null, + [createFunctionParam('params', optionsType, true)], + body, + ), + ); + } - const hookFunc = t.functionDeclaration( - t.identifier(hookName), - [optionsParam], - t.blockStatement(hookBodyStatements) + const content = generateHookFileCode( + `Custom mutation hook for ${operation.name}`, + statements, ); - const hookExport = t.exportNamedDeclaration(hookFunc); - statements.push(hookExport); - - const code = generateCode(statements); - const content = getGeneratedFileHeader(`Custom mutation hook for ${operation.name}`) + '\n\n' + code; return { fileName, @@ -300,7 +406,6 @@ function generateCustomMutationHookInternal( export interface GenerateAllCustomMutationHooksOptions { operations: CleanOperation[]; typeRegistry: TypeRegistry; - maxDepth?: number; skipQueryField?: boolean; reactQueryEnabled?: boolean; tableTypeNames?: Set; @@ -308,12 +413,11 @@ export interface GenerateAllCustomMutationHooksOptions { } export function generateAllCustomMutationHooks( - options: GenerateAllCustomMutationHooksOptions + options: GenerateAllCustomMutationHooksOptions, ): GeneratedCustomMutationFile[] { const { operations, typeRegistry, - maxDepth = 2, skipQueryField = true, reactQueryEnabled = true, tableTypeNames, @@ -326,12 +430,11 @@ export function generateAllCustomMutationHooks( generateCustomMutationHook({ operation, typeRegistry, - maxDepth, skipQueryField, reactQueryEnabled, tableTypeNames, useCentralizedKeys, - }) + }), ) .filter((result): result is GeneratedCustomMutationFile => result !== null); } diff --git a/graphql/codegen/src/core/codegen/custom-queries.ts b/graphql/codegen/src/core/codegen/custom-queries.ts index daefb0eb0..1252b1f14 100644 --- a/graphql/codegen/src/core/codegen/custom-queries.ts +++ b/graphql/codegen/src/core/codegen/custom-queries.ts @@ -1,36 +1,64 @@ /** - * Custom query hook generators for non-table operations + * Custom query hook generators for non-table operations (Babel AST-based) * * Generates hooks for operations discovered via schema introspection * that are NOT table CRUD operations (e.g., currentUser, nodeById, etc.) * + * Delegates to ORM custom query operations: + * getClient().query.operationName(args, { select }).unwrap() + * * Output structure: * queries/ * useCurrentUserQuery.ts * useNodeQuery.ts * ... */ -import type { - CleanOperation, - CleanArgument, - TypeRegistry, -} from '../../types/schema'; import * as t from '@babel/types'; -import { generateCode, addJSDocComment, typedParam, createTypedCallExpression } from './babel-ast'; -import { buildCustomQueryString } from './schema-gql-ast'; + +import type { CleanOperation, TypeRegistry } from '../../types/schema'; +import { asConst } from './babel-ast'; import { - typeRefToTsType, - isTypeRequired, - getOperationHookName, + addJSDocComment, + buildSelectionArgsCall, + callExpr, + constDecl, + createFunctionParam, + createImportDeclaration, + createSAndTDataTypeParams, + createSTypeParam, + createTDataTypeParam, + createTypeReExport, + customSelectResultTypeLiteral, + destructureParamsWithSelection, + exportAsyncDeclareFunction, + exportAsyncFunction, + exportDeclareFunction, + exportFunction, + generateHookFileCode, + getClientCustomCallUnwrap, + objectProp, + omitType, + returnUseQuery, + selectionConfigType, + spreadObj, + sRef, + typeRef, + useQueryOptionsImplType, + useQueryOptionsType, + voidStatement, + wrapInferSelectResultType, +} from './hooks-ast'; +import { getSelectTypeName } from './select-helpers'; +import { + createTypeTracker, getOperationFileName, - getOperationVariablesTypeName, - getOperationResultTypeName, - getDocumentConstName, + getOperationHookName, getQueryKeyName, - createTypeTracker, - type TypeTracker, + getTypeBaseName, + isTypeRequired, + typeRefToTsType, } from './type-resolver'; -import { ucFirst, getGeneratedFileHeader } from './utils'; +import { ucFirst } from './utils'; export interface GeneratedCustomQueryFile { fileName: string; @@ -41,40 +69,18 @@ export interface GeneratedCustomQueryFile { export interface GenerateCustomQueryHookOptions { operation: CleanOperation; typeRegistry: TypeRegistry; - maxDepth?: number; skipQueryField?: boolean; reactQueryEnabled?: boolean; tableTypeNames?: Set; useCentralizedKeys?: boolean; } -interface VariablesProp { - name: string; - type: string; - optional: boolean; - docs?: string[]; -} - -function generateVariablesProperties( - args: CleanArgument[], - tracker?: TypeTracker -): VariablesProp[] { - return args.map((arg) => ({ - name: arg.name, - type: typeRefToTsType(arg.type, tracker), - optional: !isTypeRequired(arg.type), - docs: arg.description ? [arg.description] : undefined, - })); -} - export function generateCustomQueryHook( - options: GenerateCustomQueryHookOptions + options: GenerateCustomQueryHookOptions, ): GeneratedCustomQueryFile { const { operation, typeRegistry, - maxDepth = 2, - skipQueryField = true, reactQueryEnabled = true, tableTypeNames, useCentralizedKeys = true, @@ -82,458 +88,1004 @@ export function generateCustomQueryHook( const hookName = getOperationHookName(operation.name, 'query'); const fileName = getOperationFileName(operation.name, 'query'); - const variablesTypeName = getOperationVariablesTypeName(operation.name, 'query'); - const resultTypeName = getOperationResultTypeName(operation.name, 'query'); - const documentConstName = getDocumentConstName(operation.name, 'query'); const queryKeyName = getQueryKeyName(operation.name); + const varTypeName = `${ucFirst(operation.name)}Variables`; const tracker = createTypeTracker({ tableTypeNames }); - const queryDocument = buildCustomQueryString({ - operation, - typeRegistry, - maxDepth, - skipQueryField, - }); - - const statements: t.Statement[] = []; - - const variablesProps = - operation.args.length > 0 - ? generateVariablesProperties(operation.args, tracker) - : []; + const hasArgs = operation.args.length > 0; + const hasRequiredArgs = operation.args.some((arg) => + isTypeRequired(arg.type), + ); const resultType = typeRefToTsType(operation.returnType, tracker); + for (const arg of operation.args) { + typeRefToTsType(arg.type, tracker); + } + + const selectTypeName = getSelectTypeName(operation.returnType); + const payloadTypeName = getTypeBaseName(operation.returnType); + const hasSelect = !!selectTypeName && !!payloadTypeName; - const schemaTypes = tracker.getImportableTypes(); - const tableTypes = tracker.getTableTypes(); + const statements: t.Statement[] = []; + // Imports if (reactQueryEnabled) { - const reactQueryImport = t.importDeclaration( - [t.importSpecifier(t.identifier('useQuery'), t.identifier('useQuery'))], - t.stringLiteral('@tanstack/react-query') + statements.push( + createImportDeclaration('@tanstack/react-query', ['useQuery']), ); - statements.push(reactQueryImport); - const reactQueryTypeImport = t.importDeclaration( - [ - t.importSpecifier(t.identifier('UseQueryOptions'), t.identifier('UseQueryOptions')), - t.importSpecifier(t.identifier('QueryClient'), t.identifier('QueryClient')), - ], - t.stringLiteral('@tanstack/react-query') + statements.push( + createImportDeclaration( + '@tanstack/react-query', + ['UseQueryOptions', 'UseQueryResult', 'QueryClient'], + true, + ), ); - reactQueryTypeImport.importKind = 'type'; - statements.push(reactQueryTypeImport); } - const clientImport = t.importDeclaration( - [t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], - t.stringLiteral('../client') + statements.push(createImportDeclaration('../client', ['getClient'])); + statements.push( + createImportDeclaration('../selection', ['buildSelectionArgs']), ); - statements.push(clientImport); - const clientTypeImport = t.importDeclaration( - [t.importSpecifier(t.identifier('ExecuteOptions'), t.identifier('ExecuteOptions'))], - t.stringLiteral('../client') + statements.push( + createImportDeclaration('../selection', ['SelectionConfig'], true), ); - clientTypeImport.importKind = 'type'; - statements.push(clientTypeImport); - if (tableTypes.length > 0) { - const typesImport = t.importDeclaration( - tableTypes.map((tt) => t.importSpecifier(t.identifier(tt), t.identifier(tt))), - t.stringLiteral('../types') + if (useCentralizedKeys) { + statements.push( + createImportDeclaration('../query-keys', ['customQueryKeys']), ); - typesImport.importKind = 'type'; - statements.push(typesImport); } - if (schemaTypes.length > 0) { - const schemaTypesImport = t.importDeclaration( - schemaTypes.map((st) => t.importSpecifier(t.identifier(st), t.identifier(st))), - t.stringLiteral('../schema-types') + if (hasArgs) { + statements.push( + createImportDeclaration('../../orm/query', [varTypeName], true), ); - schemaTypesImport.importKind = 'type'; - statements.push(schemaTypesImport); } - if (useCentralizedKeys) { - const queryKeyImport = t.importDeclaration( - [t.importSpecifier(t.identifier('customQueryKeys'), t.identifier('customQueryKeys'))], - t.stringLiteral('../query-keys') + const inputTypeImports: string[] = []; + if (hasSelect) { + inputTypeImports.push(selectTypeName!); + inputTypeImports.push(payloadTypeName!); + } else { + const baseName = getTypeBaseName(operation.returnType); + if (baseName && !tracker.referencedTypes.has('__skip__')) { + for (const refType of tracker.referencedTypes) { + if (!inputTypeImports.includes(refType)) { + inputTypeImports.push(refType); + } + } + } + } + if (inputTypeImports.length > 0) { + statements.push( + createImportDeclaration('../../orm/input-types', inputTypeImports, true), ); - statements.push(queryKeyImport); } - const queryDocConst = t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier(documentConstName), - t.templateLiteral( - [t.templateElement({ raw: '\n' + queryDocument, cooked: '\n' + queryDocument }, true)], - [] - ) - ), - ]); - const queryDocExport = t.exportNamedDeclaration(queryDocConst); - addJSDocComment(queryDocExport, ['GraphQL query document']); - statements.push(queryDocExport); - - if (operation.args.length > 0) { - const variablesInterfaceProps = variablesProps.map((vp) => { - const prop = t.tsPropertySignature( - t.identifier(vp.name), - t.tsTypeAnnotation(t.tsTypeReference(t.identifier(vp.type))) - ); - prop.optional = vp.optional; - return prop; - }); - const variablesInterface = t.tsInterfaceDeclaration( - t.identifier(variablesTypeName), - null, - null, - t.tsInterfaceBody(variablesInterfaceProps) + if (hasSelect) { + statements.push( + createImportDeclaration( + '../../orm/select-types', + ['InferSelectResult', 'StrictSelect'], + true, + ), ); - statements.push(t.exportNamedDeclaration(variablesInterface)); } - const resultInterfaceBody = t.tsInterfaceBody([ - t.tsPropertySignature( - t.identifier(operation.name), - t.tsTypeAnnotation(t.tsTypeReference(t.identifier(resultType))) - ), - ]); - const resultInterface = t.tsInterfaceDeclaration( - t.identifier(resultTypeName), - null, - null, - resultInterfaceBody - ); - statements.push(t.exportNamedDeclaration(resultInterface)); + // Re-exports + if (hasArgs) { + statements.push(createTypeReExport([varTypeName], '../../orm/query')); + } + if (hasSelect) { + statements.push( + createTypeReExport([selectTypeName!], '../../orm/input-types'), + ); + } + // Query key if (useCentralizedKeys) { - const queryKeyConst = t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier(queryKeyName), - t.memberExpression(t.identifier('customQueryKeys'), t.identifier(operation.name)) - ), - ]); - const queryKeyExport = t.exportNamedDeclaration(queryKeyConst); - addJSDocComment(queryKeyExport, ['Query key factory - re-exported from query-keys.ts']); - statements.push(queryKeyExport); - } else if (operation.args.length > 0) { - const queryKeyArrow = t.arrowFunctionExpression( - [typedParam('variables', t.tsTypeReference(t.identifier(variablesTypeName)), true)], - t.tsAsExpression( - t.arrayExpression([t.stringLiteral(operation.name), t.identifier('variables')]), - t.tsTypeReference(t.identifier('const')) - ) + const keyDecl = t.exportNamedDeclaration( + t.variableDeclaration('const', [ + t.variableDeclarator( + t.identifier(queryKeyName), + t.memberExpression( + t.identifier('customQueryKeys'), + t.identifier(operation.name), + ), + ), + ]), ); - const queryKeyConst = t.variableDeclaration('const', [ - t.variableDeclarator(t.identifier(queryKeyName), queryKeyArrow), + addJSDocComment(keyDecl, [ + 'Query key factory - re-exported from query-keys.ts', ]); - const queryKeyExport = t.exportNamedDeclaration(queryKeyConst); - addJSDocComment(queryKeyExport, ['Query key factory for caching']); - statements.push(queryKeyExport); + statements.push(keyDecl); + } else if (hasArgs) { + const keyFn = t.arrowFunctionExpression( + [createFunctionParam('variables', typeRef(varTypeName), true)], + asConst( + t.arrayExpression([ + t.stringLiteral(operation.name), + t.identifier('variables'), + ]), + ), + ); + const keyDecl = t.exportNamedDeclaration( + t.variableDeclaration('const', [ + t.variableDeclarator(t.identifier(queryKeyName), keyFn), + ]), + ); + addJSDocComment(keyDecl, ['Query key factory for caching']); + statements.push(keyDecl); } else { - const queryKeyArrow = t.arrowFunctionExpression( + const keyFn = t.arrowFunctionExpression( [], - t.tsAsExpression( - t.arrayExpression([t.stringLiteral(operation.name)]), - t.tsTypeReference(t.identifier('const')) - ) + asConst(t.arrayExpression([t.stringLiteral(operation.name)])), ); - const queryKeyConst = t.variableDeclaration('const', [ - t.variableDeclarator(t.identifier(queryKeyName), queryKeyArrow), - ]); - const queryKeyExport = t.exportNamedDeclaration(queryKeyConst); - addJSDocComment(queryKeyExport, ['Query key factory for caching']); - statements.push(queryKeyExport); + const keyDecl = t.exportNamedDeclaration( + t.variableDeclaration('const', [ + t.variableDeclarator(t.identifier(queryKeyName), keyFn), + ]), + ); + addJSDocComment(keyDecl, ['Query key factory for caching']); + statements.push(keyDecl); } + // Helper to build query key call expression + const buildQueryKeyCall = (withVars: boolean) => { + if (useCentralizedKeys) { + return withVars + ? callExpr(t.identifier(queryKeyName), [t.identifier('variables')]) + : callExpr(t.identifier(queryKeyName), []); + } + return withVars + ? callExpr(t.identifier(queryKeyName), [t.identifier('variables')]) + : callExpr(t.identifier(queryKeyName), []); + }; + + // Helper to build the fields+StrictSelect intersection type + const fieldsSelectionType = (s: t.TSType) => + t.tsParenthesizedType( + t.tsIntersectionType([ + t.tsTypeLiteral([ + t.tsPropertySignature(t.identifier('fields'), t.tsTypeAnnotation(s)), + ]), + typeRef('StrictSelect', [s, typeRef(selectTypeName!)]), + ]), + ); + + const selectedResultType = (sel: t.TSType) => + customSelectResultTypeLiteral( + operation.name, + operation.returnType, + payloadTypeName!, + sel, + ); + + // Hook if (reactQueryEnabled) { - const hasArgs = operation.args.length > 0; - const hasRequiredArgs = operation.args.some((arg) => isTypeRequired(arg.type)); + const description = + operation.description || `Query hook for ${operation.name}`; + const argNames = operation.args.map((a) => a.name).join(', '); + const exampleCall = hasArgs + ? hasSelect + ? `${hookName}({ variables: { ${argNames} }, selection: { fields: { id: true } } })` + : `${hookName}({ variables: { ${argNames} } })` + : hasSelect + ? `${hookName}({ selection: { fields: { id: true } } })` + : `${hookName}()`; - const hookBodyStatements: t.Statement[] = []; - const useQueryOptions: (t.ObjectProperty | t.SpreadElement)[] = []; + if (hasSelect) { + // Overload 1: with selection.fields + const o1Props: t.TSPropertySignature[] = []; + if (hasArgs) { + const varType = hasRequiredArgs + ? typeRef(varTypeName) + : t.tsUnionType([typeRef(varTypeName), t.tsUndefinedKeyword()]); + o1Props.push( + t.tsPropertySignature( + t.identifier('variables'), + t.tsTypeAnnotation(varType), + ), + ); + } + o1Props.push( + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(fieldsSelectionType(sRef())), + ), + ); + const o1ParamType = t.tsIntersectionType([ + t.tsTypeLiteral(o1Props), + omitType( + typeRef('UseQueryOptions', [ + selectedResultType(sRef()), + typeRef('Error'), + typeRef('TData'), + ]), + ['queryKey', 'queryFn'], + ), + ]); + const o1 = exportDeclareFunction( + hookName, + createSAndTDataTypeParams(selectTypeName!, selectedResultType(sRef())), + [createFunctionParam('params', o1ParamType)], + typeRef('UseQueryResult', [typeRef('TData')]), + ); + addJSDocComment(o1, [ + description, + '', + '@example', + '```tsx', + `const { data, isLoading } = ${exampleCall};`, + '', + `if (data?.${operation.name}) {`, + ` console.log(data.${operation.name});`, + '}', + '```', + ]); + statements.push(o1); - if (hasArgs) { - useQueryOptions.push( - t.objectProperty( - t.identifier('queryKey'), - t.callExpression(t.identifier(queryKeyName), [t.identifier('variables')]) - ) + // Implementation + const implProps: t.TSPropertySignature[] = []; + if (hasArgs) { + const varProp = t.tsPropertySignature( + t.identifier('variables'), + t.tsTypeAnnotation(typeRef(varTypeName)), + ); + if (!hasRequiredArgs) varProp.optional = true; + implProps.push(varProp); + } + const implSelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName!))), ); - useQueryOptions.push( - t.objectProperty( - t.identifier('queryFn'), - t.arrowFunctionExpression( - [], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(documentConstName), t.identifier('variables')], - [ - t.tsTypeReference(t.identifier(resultTypeName)), - t.tsTypeReference(t.identifier(variablesTypeName)), - ] - ) - ) - ) + implProps.push(implSelProp); + const implParamType = t.tsIntersectionType([ + t.tsTypeLiteral(implProps), + useQueryOptionsImplType(), + ]); + const implParam = createFunctionParam( + 'params', + implParamType, + false, ); - if (hasRequiredArgs) { - useQueryOptions.push( + + const body: t.Statement[] = []; + if (hasArgs) { + body.push( + constDecl( + 'variables', + hasRequiredArgs + ? t.memberExpression( + t.identifier('params'), + t.identifier('variables'), + ) + : t.logicalExpression( + '??', + t.memberExpression(t.identifier('params'), t.identifier('variables')), + t.objectExpression([]), + ), + ), + ); + } + body.push(buildSelectionArgsCall(selectTypeName!)); + + if (hasArgs) { + const destructPattern = t.objectPattern([ t.objectProperty( - t.identifier('enabled'), - t.logicalExpression( - '&&', - t.unaryExpression('!', t.unaryExpression('!', t.identifier('variables'))), - t.binaryExpression( - '!==', - t.optionalMemberExpression( - t.identifier('options'), - t.identifier('enabled'), + t.identifier('variables'), + t.identifier('_variables'), + false, + false, + ), + t.objectProperty( + t.identifier('selection'), + t.identifier('_selection'), + false, + false, + ), + t.restElement(t.identifier('queryOptions')), + ]); + body.push( + t.variableDeclaration('const', [ + t.variableDeclarator( + destructPattern, + t.logicalExpression( + '??', + t.identifier('params'), + t.objectExpression([]), + ), + ), + ]), + ); + body.push(voidStatement('_variables')); + body.push(voidStatement('_selection')); + } else { + body.push(destructureParamsWithSelection('queryOptions')); + body.push(voidStatement('_selection')); + } + + const selectArgExpr = t.objectExpression([ + objectProp( + 'select', + t.memberExpression(t.identifier('args'), t.identifier('select')), + ), + ]); + const queryFnArgs = hasArgs + ? [ + hasRequiredArgs + ? t.tsNonNullExpression(t.identifier('variables')) + : t.identifier('variables'), + selectArgExpr, + ] + : [selectArgExpr]; + const queryFnExpr = t.arrowFunctionExpression( + [], + getClientCustomCallUnwrap( + 'query', + operation.name, + queryFnArgs as t.Expression[], + ), + ); + + const extraProps: (t.ObjectProperty | t.SpreadElement)[] = []; + const enabledExpr = hasRequiredArgs + ? t.logicalExpression( + '&&', + t.unaryExpression( + '!', + t.unaryExpression('!', t.identifier('variables')), + ), + t.binaryExpression( + '!==', + t.optionalMemberExpression( + t.identifier('params'), + t.identifier('enabled'), + false, + true, + ), + t.booleanLiteral(false), + ), + ) + : undefined; + extraProps.push(spreadObj(t.identifier('queryOptions'))); + + body.push( + returnUseQuery( + buildQueryKeyCall(hasArgs), + queryFnExpr, + extraProps, + enabledExpr, + ), + ); + statements.push(exportFunction(hookName, null, [implParam], body)); + } else { + // Without select: simple hook (scalar return type) + const resultTypeLiteral = t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier(operation.name), + t.tsTypeAnnotation(typeRef(resultType)), + ), + ]); + + const optType = omitType( + typeRef('UseQueryOptions', [ + resultTypeLiteral, + typeRef('Error'), + typeRef('TData'), + ]), + ['queryKey', 'queryFn'], + ); + + let paramType: t.TSType; + if (hasArgs) { + const varProp = t.tsPropertySignature( + t.identifier('variables'), + t.tsTypeAnnotation(typeRef(varTypeName)), + ); + if (!hasRequiredArgs) varProp.optional = true; + paramType = t.tsIntersectionType([t.tsTypeLiteral([varProp]), optType]); + } else { + paramType = optType; + } + + const implParam = createFunctionParam( + 'params', + paramType, + !hasRequiredArgs, + ); + const hookDecl = exportDeclareFunction( + hookName, + createTDataTypeParam(resultTypeLiteral), + [implParam], + typeRef('UseQueryResult', [typeRef('TData')]), + ); + addJSDocComment(hookDecl, [ + description, + '', + '@example', + '```tsx', + `const { data, isLoading } = ${exampleCall};`, + '', + `if (data?.${operation.name}) {`, + ` console.log(data.${operation.name});`, + '}', + '```', + ]); + + const body: t.Statement[] = []; + if (hasArgs) { + body.push( + constDecl( + 'variables', + hasRequiredArgs + ? t.optionalMemberExpression( + t.identifier('params'), + t.identifier('variables'), false, - true + true, + ) + : t.logicalExpression( + '??', + t.optionalMemberExpression( + t.identifier('params'), + t.identifier('variables'), + false, + true, + ), + t.objectExpression([]), ), - t.booleanLiteral(false) - ) - ) - ) + ), + ); + const destructPattern = t.objectPattern([ + t.objectProperty( + t.identifier('variables'), + t.identifier('_variables'), + false, + false, + ), + t.restElement(t.identifier('queryOptions')), + ]); + body.push( + t.variableDeclaration('const', [ + t.variableDeclarator( + destructPattern, + t.logicalExpression( + '??', + t.identifier('params'), + t.objectExpression([]), + ), + ), + ]), + ); + body.push(voidStatement('_variables')); + } else { + body.push( + constDecl( + 'queryOptions', + t.logicalExpression( + '??', + t.identifier('params'), + t.objectExpression([]), + ), + ), ); } - } else { - useQueryOptions.push( - t.objectProperty( - t.identifier('queryKey'), - t.callExpression(t.identifier(queryKeyName), []) - ) + + const queryFnArgs = hasArgs + ? [ + hasRequiredArgs + ? t.tsNonNullExpression(t.identifier('variables')) + : t.identifier('variables'), + ] + : []; + const queryFnExpr = t.arrowFunctionExpression( + [], + getClientCustomCallUnwrap( + 'query', + operation.name, + queryFnArgs as t.Expression[], + ), ); - useQueryOptions.push( - t.objectProperty( - t.identifier('queryFn'), - t.arrowFunctionExpression( - [], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(documentConstName)], - [t.tsTypeReference(t.identifier(resultTypeName))] - ) + + const enabledExpr = hasRequiredArgs + ? t.logicalExpression( + '&&', + t.unaryExpression( + '!', + t.unaryExpression('!', t.identifier('variables')), + ), + t.binaryExpression( + '!==', + t.optionalMemberExpression( + t.identifier('params'), + t.identifier('enabled'), + false, + true, + ), + t.booleanLiteral(false), + ), ) - ) + : undefined; + + body.push( + returnUseQuery( + buildQueryKeyCall(hasArgs), + queryFnExpr, + [spreadObj(t.identifier('queryOptions'))], + enabledExpr, + ), + ); + + // We need the implementation version (not declare), with return type + statements.push(hookDecl); + statements.push( + exportFunction( + hookName, + createTDataTypeParam(resultTypeLiteral), + [implParam], + body, + typeRef('UseQueryResult', [typeRef('TData')]), + ), ); } - useQueryOptions.push(t.spreadElement(t.identifier('options'))); + } - hookBodyStatements.push( - t.returnStatement( - t.callExpression(t.identifier('useQuery'), [t.objectExpression(useQueryOptions)]) - ) - ); + // Fetch function (non-hook) + const fetchFnName = `fetch${ucFirst(operation.name)}Query`; + const fetchArgNames = operation.args.map((a) => a.name).join(', '); + const fetchExampleCall = hasArgs + ? hasSelect + ? `${fetchFnName}({ variables: { ${fetchArgNames} }, selection: { fields: { id: true } } })` + : `${fetchFnName}({ variables: { ${fetchArgNames} } })` + : hasSelect + ? `${fetchFnName}({ selection: { fields: { id: true } } })` + : `${fetchFnName}()`; - const hookParams: t.Identifier[] = []; + if (hasSelect) { + // Overload 1: with fields + const f1Props: t.TSPropertySignature[] = []; if (hasArgs) { - hookParams.push( - typedParam('variables', t.tsTypeReference(t.identifier(variablesTypeName)), !hasRequiredArgs) + const varType = hasRequiredArgs + ? typeRef(varTypeName) + : t.tsUnionType([typeRef(varTypeName), t.tsUndefinedKeyword()]); + f1Props.push( + t.tsPropertySignature( + t.identifier('variables'), + t.tsTypeAnnotation(varType), + ), ); } - const optionsTypeStr = `Omit, 'queryKey' | 'queryFn'>`; - const optionsParam = t.identifier('options'); - optionsParam.optional = true; - optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(optionsTypeStr))); - hookParams.push(optionsParam); - - const hookFunc = t.functionDeclaration( - t.identifier(hookName), - hookParams, - t.blockStatement(hookBodyStatements) + f1Props.push( + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(fieldsSelectionType(sRef())), + ), ); - const hookExport = t.exportNamedDeclaration(hookFunc); - - const description = operation.description || `Query hook for ${operation.name}`; - const argNames = operation.args.map((a) => a.name).join(', '); - const exampleCall = hasArgs ? `${hookName}({ ${argNames} })` : `${hookName}()`; - addJSDocComment(hookExport, [ - description, + const f1Decl = exportAsyncDeclareFunction( + fetchFnName, + createSTypeParam(selectTypeName!), + [createFunctionParam('params', t.tsTypeLiteral(f1Props))], + typeRef('Promise', [selectedResultType(sRef())]), + ); + addJSDocComment(f1Decl, [ + `Fetch ${operation.name} without React hooks`, '', '@example', - '```tsx', - `const { data, isLoading } = ${exampleCall};`, - '', - `if (data?.${operation.name}) {`, - ` console.log(data.${operation.name});`, - '}', + '```ts', + `const data = await ${fetchExampleCall};`, '```', ]); - statements.push(hookExport); - } - - const fetchFnName = `fetch${ucFirst(operation.name)}Query`; - const hasArgs = operation.args.length > 0; - const hasRequiredArgs = operation.args.some((arg) => isTypeRequired(arg.type)); + statements.push(f1Decl); - const fetchBodyStatements: t.Statement[] = []; - if (hasArgs) { - fetchBodyStatements.push( - t.returnStatement( - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(documentConstName), t.identifier('variables'), t.identifier('options')], - [ - t.tsTypeReference(t.identifier(resultTypeName)), - t.tsTypeReference(t.identifier(variablesTypeName)), - ] - ) - ) + // Implementation + const fImplProps: t.TSPropertySignature[] = []; + if (hasArgs) { + const varProp = t.tsPropertySignature( + t.identifier('variables'), + t.tsTypeAnnotation(typeRef(varTypeName)), + ); + if (!hasRequiredArgs) varProp.optional = true; + fImplProps.push(varProp); + } + const fImplSelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName!))), ); - } else { - fetchBodyStatements.push( + fImplProps.push(fImplSelProp); + + const fBody: t.Statement[] = []; + if (hasArgs) { + fBody.push( + constDecl( + 'variables', + hasRequiredArgs + ? t.memberExpression(t.identifier('params'), t.identifier('variables')) + : t.logicalExpression( + '??', + t.memberExpression(t.identifier('params'), t.identifier('variables')), + t.objectExpression([]), + ), + ), + ); + } + fBody.push(buildSelectionArgsCall(selectTypeName!)); + const selectArgExpr = t.objectExpression([ + objectProp( + 'select', + t.memberExpression(t.identifier('args'), t.identifier('select')), + ), + ]); + const fCallArgs = hasArgs + ? [ + hasRequiredArgs + ? t.tsNonNullExpression(t.identifier('variables')) + : t.identifier('variables'), + selectArgExpr, + ] + : [selectArgExpr]; + fBody.push( t.returnStatement( - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(documentConstName), t.identifier('undefined'), t.identifier('options')], - [t.tsTypeReference(t.identifier(resultTypeName))] - ) - ) + getClientCustomCallUnwrap( + 'query', + operation.name, + fCallArgs as t.Expression[], + ), + ), ); - } - - const fetchParams: t.Identifier[] = []; - if (hasArgs) { - fetchParams.push( - typedParam('variables', t.tsTypeReference(t.identifier(variablesTypeName)), !hasRequiredArgs) + statements.push( + exportAsyncFunction( + fetchFnName, + null, + [ + createFunctionParam( + 'params', + t.tsTypeLiteral(fImplProps), + false, + ), + ], + fBody, + ), ); + } else { + const fBody: t.Statement[] = []; + if (hasArgs) { + const fProps: t.TSPropertySignature[] = []; + const varProp = t.tsPropertySignature( + t.identifier('variables'), + t.tsTypeAnnotation(typeRef(varTypeName)), + ); + if (!hasRequiredArgs) varProp.optional = true; + fProps.push(varProp); + fBody.push( + constDecl( + 'variables', + hasRequiredArgs + ? t.optionalMemberExpression( + t.identifier('params'), + t.identifier('variables'), + false, + true, + ) + : t.logicalExpression( + '??', + t.optionalMemberExpression( + t.identifier('params'), + t.identifier('variables'), + false, + true, + ), + t.objectExpression([]), + ), + ), + ); + const fCallArgs = hasRequiredArgs + ? [t.tsNonNullExpression(t.identifier('variables'))] + : [t.identifier('variables')]; + fBody.push( + t.returnStatement( + getClientCustomCallUnwrap( + 'query', + operation.name, + fCallArgs as t.Expression[], + ), + ), + ); + const fDecl = exportAsyncFunction( + fetchFnName, + null, + [ + createFunctionParam( + 'params', + t.tsTypeLiteral(fProps), + !hasRequiredArgs, + ), + ], + fBody, + ); + addJSDocComment(fDecl, [ + `Fetch ${operation.name} without React hooks`, + '', + '@example', + '```ts', + `const data = await ${fetchExampleCall};`, + '```', + ]); + statements.push(fDecl); + } else { + fBody.push( + t.returnStatement( + getClientCustomCallUnwrap('query', operation.name, []), + ), + ); + const fDecl = exportAsyncFunction(fetchFnName, null, [], fBody); + addJSDocComment(fDecl, [ + `Fetch ${operation.name} without React hooks`, + '', + '@example', + '```ts', + `const data = await ${fetchExampleCall};`, + '```', + ]); + statements.push(fDecl); + } } - fetchParams.push(typedParam('options', t.tsTypeReference(t.identifier('ExecuteOptions')), true)); - - const fetchFunc = t.functionDeclaration( - t.identifier(fetchFnName), - fetchParams, - t.blockStatement(fetchBodyStatements) - ); - fetchFunc.async = true; - fetchFunc.returnType = t.tsTypeAnnotation( - t.tsTypeReference( - t.identifier('Promise'), - t.tsTypeParameterInstantiation([t.tsTypeReference(t.identifier(resultTypeName))]) - ) - ); - const fetchExport = t.exportNamedDeclaration(fetchFunc); - - const argNames = operation.args.map((a) => a.name).join(', '); - const fetchExampleCall = hasArgs ? `${fetchFnName}({ ${argNames} })` : `${fetchFnName}()`; - addJSDocComment(fetchExport, [ - `Fetch ${operation.name} without React hooks`, - '', - '@example', - '```ts', - `const data = await ${fetchExampleCall};`, - '```', - ]); - statements.push(fetchExport); + // Prefetch function if (reactQueryEnabled) { const prefetchFnName = `prefetch${ucFirst(operation.name)}Query`; + const prefetchArgNames = operation.args.map((a) => a.name).join(', '); + const prefetchExampleCall = hasArgs + ? hasSelect + ? `${prefetchFnName}(queryClient, { variables: { ${prefetchArgNames} }, selection: { fields: { id: true } } })` + : `${prefetchFnName}(queryClient, { variables: { ${prefetchArgNames} } })` + : hasSelect + ? `${prefetchFnName}(queryClient, { selection: { fields: { id: true } } })` + : `${prefetchFnName}(queryClient)`; - const prefetchBodyStatements: t.Statement[] = []; - const prefetchQueryOptions: t.ObjectProperty[] = []; - - if (hasArgs) { - prefetchQueryOptions.push( - t.objectProperty( - t.identifier('queryKey'), - t.callExpression(t.identifier(queryKeyName), [t.identifier('variables')]) - ) + if (hasSelect) { + // Overload 1: with fields + const p1Props: t.TSPropertySignature[] = []; + if (hasArgs) { + const varType = hasRequiredArgs + ? typeRef(varTypeName) + : t.tsUnionType([typeRef(varTypeName), t.tsUndefinedKeyword()]); + p1Props.push( + t.tsPropertySignature( + t.identifier('variables'), + t.tsTypeAnnotation(varType), + ), + ); + } + p1Props.push( + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(fieldsSelectionType(sRef())), + ), ); - prefetchQueryOptions.push( - t.objectProperty( - t.identifier('queryFn'), - t.arrowFunctionExpression( - [], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(documentConstName), t.identifier('variables'), t.identifier('options')], - [ - t.tsTypeReference(t.identifier(resultTypeName)), - t.tsTypeReference(t.identifier(variablesTypeName)), - ] - ) - ) - ) + const p1Decl = exportAsyncDeclareFunction( + prefetchFnName, + createSTypeParam(selectTypeName!), + [ + createFunctionParam('queryClient', typeRef('QueryClient')), + createFunctionParam('params', t.tsTypeLiteral(p1Props)), + ], + typeRef('Promise', [t.tsVoidKeyword()]), ); - } else { - prefetchQueryOptions.push( - t.objectProperty( - t.identifier('queryKey'), - t.callExpression(t.identifier(queryKeyName), []) - ) + addJSDocComment(p1Decl, [ + `Prefetch ${operation.name} for SSR or cache warming`, + '', + '@example', + '```ts', + `await ${prefetchExampleCall};`, + '```', + ]); + statements.push(p1Decl); + + // Implementation + const pImplProps: t.TSPropertySignature[] = []; + if (hasArgs) { + const varProp = t.tsPropertySignature( + t.identifier('variables'), + t.tsTypeAnnotation(typeRef(varTypeName)), + ); + if (!hasRequiredArgs) varProp.optional = true; + pImplProps.push(varProp); + } + const pImplSelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName!))), ); - prefetchQueryOptions.push( - t.objectProperty( - t.identifier('queryFn'), - t.arrowFunctionExpression( - [], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(documentConstName), t.identifier('undefined'), t.identifier('options')], - [t.tsTypeReference(t.identifier(resultTypeName))] - ) - ) - ) + pImplProps.push(pImplSelProp); + + const pBody: t.Statement[] = []; + if (hasArgs) { + pBody.push( + constDecl( + 'variables', + hasRequiredArgs + ? t.memberExpression( + t.identifier('params'), + t.identifier('variables'), + ) + : t.logicalExpression( + '??', + t.memberExpression(t.identifier('params'), t.identifier('variables')), + t.objectExpression([]), + ), + ), + ); + } + pBody.push(buildSelectionArgsCall(selectTypeName!)); + const selectArgExpr = t.objectExpression([ + objectProp( + 'select', + t.memberExpression(t.identifier('args'), t.identifier('select')), + ), + ]); + const pCallArgs = hasArgs + ? [ + hasRequiredArgs + ? t.tsNonNullExpression(t.identifier('variables')) + : t.identifier('variables'), + selectArgExpr, + ] + : [selectArgExpr]; + const prefetchQueryCall = callExpr( + t.memberExpression( + t.identifier('queryClient'), + t.identifier('prefetchQuery'), + ), + [ + t.objectExpression([ + objectProp('queryKey', buildQueryKeyCall(hasArgs)), + objectProp( + 'queryFn', + t.arrowFunctionExpression( + [], + getClientCustomCallUnwrap( + 'query', + operation.name, + pCallArgs as t.Expression[], + ), + ), + ), + ]), + ], ); - } + pBody.push(t.expressionStatement(t.awaitExpression(prefetchQueryCall))); + statements.push( + exportAsyncFunction( + prefetchFnName, + null, + [ + createFunctionParam('queryClient', typeRef('QueryClient')), + createFunctionParam( + 'params', + t.tsTypeLiteral(pImplProps), + false, + ), + ], + pBody, + typeRef('Promise', [t.tsVoidKeyword()]), + ), + ); + } else { + // Without select + const pBody: t.Statement[] = []; + const pParams: t.Identifier[] = [ + createFunctionParam('queryClient', typeRef('QueryClient')), + ]; - prefetchBodyStatements.push( - t.expressionStatement( - t.awaitExpression( - t.callExpression( - t.memberExpression(t.identifier('queryClient'), t.identifier('prefetchQuery')), - [t.objectExpression(prefetchQueryOptions)] - ) - ) - ) - ); + if (hasArgs) { + const pProps: t.TSPropertySignature[] = []; + const varProp = t.tsPropertySignature( + t.identifier('variables'), + t.tsTypeAnnotation(typeRef(varTypeName)), + ); + if (!hasRequiredArgs) varProp.optional = true; + pProps.push(varProp); + pParams.push( + createFunctionParam( + 'params', + t.tsTypeLiteral(pProps), + !hasRequiredArgs, + ), + ); + pBody.push( + constDecl( + 'variables', + hasRequiredArgs + ? t.optionalMemberExpression( + t.identifier('params'), + t.identifier('variables'), + false, + true, + ) + : t.logicalExpression( + '??', + t.optionalMemberExpression( + t.identifier('params'), + t.identifier('variables'), + false, + true, + ), + t.objectExpression([]), + ), + ), + ); + const pCallArgs = hasRequiredArgs + ? [t.tsNonNullExpression(t.identifier('variables'))] + : [t.identifier('variables')]; + const prefetchQueryCall = callExpr( + t.memberExpression( + t.identifier('queryClient'), + t.identifier('prefetchQuery'), + ), + [ + t.objectExpression([ + objectProp('queryKey', buildQueryKeyCall(true)), + objectProp( + 'queryFn', + t.arrowFunctionExpression( + [], + getClientCustomCallUnwrap( + 'query', + operation.name, + pCallArgs as t.Expression[], + ), + ), + ), + ]), + ], + ); + pBody.push(t.expressionStatement(t.awaitExpression(prefetchQueryCall))); + } else { + const prefetchQueryCall = callExpr( + t.memberExpression( + t.identifier('queryClient'), + t.identifier('prefetchQuery'), + ), + [ + t.objectExpression([ + objectProp('queryKey', buildQueryKeyCall(false)), + objectProp( + 'queryFn', + t.arrowFunctionExpression( + [], + getClientCustomCallUnwrap('query', operation.name, []), + ), + ), + ]), + ], + ); + pBody.push(t.expressionStatement(t.awaitExpression(prefetchQueryCall))); + } - const prefetchParams: t.Identifier[] = [ - typedParam('queryClient', t.tsTypeReference(t.identifier('QueryClient'))), - ]; - if (hasArgs) { - prefetchParams.push( - typedParam('variables', t.tsTypeReference(t.identifier(variablesTypeName)), !hasRequiredArgs) + const pDecl = exportAsyncFunction( + prefetchFnName, + null, + pParams, + pBody, + typeRef('Promise', [t.tsVoidKeyword()]), ); + addJSDocComment(pDecl, [ + `Prefetch ${operation.name} for SSR or cache warming`, + '', + '@example', + '```ts', + `await ${prefetchExampleCall};`, + '```', + ]); + statements.push(pDecl); } - prefetchParams.push(typedParam('options', t.tsTypeReference(t.identifier('ExecuteOptions')), true)); - - const prefetchFunc = t.functionDeclaration( - t.identifier(prefetchFnName), - prefetchParams, - t.blockStatement(prefetchBodyStatements) - ); - prefetchFunc.async = true; - prefetchFunc.returnType = t.tsTypeAnnotation( - t.tsTypeReference( - t.identifier('Promise'), - t.tsTypeParameterInstantiation([t.tsVoidKeyword()]) - ) - ); - const prefetchExport = t.exportNamedDeclaration(prefetchFunc); - - const prefetchExampleCall = hasArgs - ? `${prefetchFnName}(queryClient, { ${argNames} })` - : `${prefetchFnName}(queryClient)`; - addJSDocComment(prefetchExport, [ - `Prefetch ${operation.name} for SSR or cache warming`, - '', - '@example', - '```ts', - `await ${prefetchExampleCall};`, - '```', - ]); - statements.push(prefetchExport); } - const code = generateCode(statements); const headerText = reactQueryEnabled ? `Custom query hook for ${operation.name}` : `Custom query functions for ${operation.name}`; - const content = getGeneratedFileHeader(headerText) + '\n\n' + code; + const content = generateHookFileCode(headerText, statements); return { fileName, @@ -545,7 +1097,6 @@ export function generateCustomQueryHook( export interface GenerateAllCustomQueryHooksOptions { operations: CleanOperation[]; typeRegistry: TypeRegistry; - maxDepth?: number; skipQueryField?: boolean; reactQueryEnabled?: boolean; tableTypeNames?: Set; @@ -553,12 +1104,11 @@ export interface GenerateAllCustomQueryHooksOptions { } export function generateAllCustomQueryHooks( - options: GenerateAllCustomQueryHooksOptions + options: GenerateAllCustomQueryHooksOptions, ): GeneratedCustomQueryFile[] { const { operations, typeRegistry, - maxDepth = 2, skipQueryField = true, reactQueryEnabled = true, tableTypeNames, @@ -571,11 +1121,10 @@ export function generateAllCustomQueryHooks( generateCustomQueryHook({ operation, typeRegistry, - maxDepth, skipQueryField, reactQueryEnabled, tableTypeNames, useCentralizedKeys, - }) + }), ); } diff --git a/graphql/codegen/src/core/codegen/gql-ast.ts b/graphql/codegen/src/core/codegen/gql-ast.ts deleted file mode 100644 index 612db24a0..000000000 --- a/graphql/codegen/src/core/codegen/gql-ast.ts +++ /dev/null @@ -1,405 +0,0 @@ -/** - * GraphQL AST builders using gql-ast - * - * Provides utilities for generating GraphQL queries and mutations via AST - * instead of string concatenation. - */ -import * as t from 'gql-ast'; -import { print } from 'graphql'; -import type { - DocumentNode, - FieldNode, - ArgumentNode, - VariableDefinitionNode, -} from 'graphql'; -import type { CleanTable, CleanField } from '../../types/schema'; -import { - getTableNames, - getAllRowsQueryName, - getSingleRowQueryName, - getCreateMutationName, - getUpdateMutationName, - getDeleteMutationName, - getFilterTypeName, - getConditionTypeName, - getOrderByTypeName, - getScalarFields, - getPrimaryKeyInfo, - ucFirst, -} from './utils'; - - - -// ============================================================================ -// Field selection builders -// ============================================================================ - -/** - * Create field selections from CleanField array - */ -function createFieldSelections(fields: CleanField[]): FieldNode[] { - return fields.map((field) => t.field({ name: field.name })); -} - -/** - * Create pageInfo selection - */ -function createPageInfoSelection(): FieldNode { - return t.field({ - name: 'pageInfo', - selectionSet: t.selectionSet({ - selections: [ - t.field({ name: 'hasNextPage' }), - t.field({ name: 'hasPreviousPage' }), - t.field({ name: 'startCursor' }), - t.field({ name: 'endCursor' }), - ], - }), - }); -} - -// ============================================================================ -// List query builder -// ============================================================================ - -export interface ListQueryConfig { - table: CleanTable; -} - -/** - * Build a list query AST for a table - */ -export function buildListQueryAST(config: ListQueryConfig): DocumentNode { - const { table } = config; - const queryName = getAllRowsQueryName(table); - const filterType = getFilterTypeName(table); - const conditionType = getConditionTypeName(table); - const orderByType = getOrderByTypeName(table); - const scalarFields = getScalarFields(table); - - // Variable definitions - all pagination arguments from PostGraphile - const variableDefinitions: VariableDefinitionNode[] = [ - t.variableDefinition({ - variable: t.variable({ name: 'first' }), - type: t.namedType({ type: 'Int' }), - }), - t.variableDefinition({ - variable: t.variable({ name: 'last' }), - type: t.namedType({ type: 'Int' }), - }), - t.variableDefinition({ - variable: t.variable({ name: 'offset' }), - type: t.namedType({ type: 'Int' }), - }), - t.variableDefinition({ - variable: t.variable({ name: 'before' }), - type: t.namedType({ type: 'Cursor' }), - }), - t.variableDefinition({ - variable: t.variable({ name: 'after' }), - type: t.namedType({ type: 'Cursor' }), - }), - t.variableDefinition({ - variable: t.variable({ name: 'filter' }), - type: t.namedType({ type: filterType }), - }), - t.variableDefinition({ - variable: t.variable({ name: 'condition' }), - type: t.namedType({ type: conditionType }), - }), - t.variableDefinition({ - variable: t.variable({ name: 'orderBy' }), - type: t.listType({ - type: t.nonNullType({ type: t.namedType({ type: orderByType }) }), - }), - }), - ]; - - // Query arguments - const args: ArgumentNode[] = [ - t.argument({ name: 'first', value: t.variable({ name: 'first' }) }), - t.argument({ name: 'last', value: t.variable({ name: 'last' }) }), - t.argument({ name: 'offset', value: t.variable({ name: 'offset' }) }), - t.argument({ name: 'before', value: t.variable({ name: 'before' }) }), - t.argument({ name: 'after', value: t.variable({ name: 'after' }) }), - t.argument({ name: 'filter', value: t.variable({ name: 'filter' }) }), - t.argument({ name: 'condition', value: t.variable({ name: 'condition' }) }), - t.argument({ name: 'orderBy', value: t.variable({ name: 'orderBy' }) }), - ]; - - // Field selections - const fieldSelections = createFieldSelections(scalarFields); - - // Connection fields - const connectionFields: FieldNode[] = [ - t.field({ name: 'totalCount' }), - t.field({ - name: 'nodes', - selectionSet: t.selectionSet({ selections: fieldSelections }), - }), - createPageInfoSelection(), - ]; - - return t.document({ - definitions: [ - t.operationDefinition({ - operation: 'query', - name: `${ucFirst(queryName)}Query`, - variableDefinitions, - selectionSet: t.selectionSet({ - selections: [ - t.field({ - name: queryName, - args, - selectionSet: t.selectionSet({ selections: connectionFields }), - }), - ], - }), - }), - ], - }); -} - -// ============================================================================ -// Single item query builder -// ============================================================================ - -export interface SingleQueryConfig { - table: CleanTable; -} - -/** - * Build a single item query AST for a table - */ -export function buildSingleQueryAST(config: SingleQueryConfig): DocumentNode { - const { table } = config; - const queryName = getSingleRowQueryName(table); - const scalarFields = getScalarFields(table); - - // Get primary key info dynamically from table constraints - const pkFields = getPrimaryKeyInfo(table); - // For simplicity, use first PK field (most common case) - const pkField = pkFields[0]; - - // Variable definitions - use dynamic PK field name and type - const variableDefinitions: VariableDefinitionNode[] = [ - t.variableDefinition({ - variable: t.variable({ name: pkField.name }), - type: t.nonNullType({ type: t.namedType({ type: pkField.gqlType }) }), - }), - ]; - - // Query arguments - use dynamic PK field name - const args: ArgumentNode[] = [ - t.argument({ name: pkField.name, value: t.variable({ name: pkField.name }) }), - ]; - - // Field selections - const fieldSelections = createFieldSelections(scalarFields); - - return t.document({ - definitions: [ - t.operationDefinition({ - operation: 'query', - name: `${ucFirst(queryName)}Query`, - variableDefinitions, - selectionSet: t.selectionSet({ - selections: [ - t.field({ - name: queryName, - args, - selectionSet: t.selectionSet({ selections: fieldSelections }), - }), - ], - }), - }), - ], - }); -} - -// ============================================================================ -// Create mutation builder -// ============================================================================ - -export interface CreateMutationConfig { - table: CleanTable; -} - -/** - * Build a create mutation AST for a table - */ -export function buildCreateMutationAST(config: CreateMutationConfig): DocumentNode { - const { table } = config; - const { typeName, singularName } = getTableNames(table); - const mutationName = getCreateMutationName(table); - const inputTypeName = `Create${typeName}Input`; - const scalarFields = getScalarFields(table); - - // Variable definitions - const variableDefinitions: VariableDefinitionNode[] = [ - t.variableDefinition({ - variable: t.variable({ name: 'input' }), - type: t.nonNullType({ type: t.namedType({ type: inputTypeName }) }), - }), - ]; - - // Mutation arguments - const args: ArgumentNode[] = [ - t.argument({ name: 'input', value: t.variable({ name: 'input' }) }), - ]; - - // Field selections - const fieldSelections = createFieldSelections(scalarFields); - - return t.document({ - definitions: [ - t.operationDefinition({ - operation: 'mutation', - name: `${ucFirst(mutationName)}Mutation`, - variableDefinitions, - selectionSet: t.selectionSet({ - selections: [ - t.field({ - name: mutationName, - args, - selectionSet: t.selectionSet({ - selections: [ - t.field({ - name: singularName, - selectionSet: t.selectionSet({ selections: fieldSelections }), - }), - ], - }), - }), - ], - }), - }), - ], - }); -} - -// ============================================================================ -// Update mutation builder -// ============================================================================ - -export interface UpdateMutationConfig { - table: CleanTable; -} - -/** - * Build an update mutation AST for a table - */ -export function buildUpdateMutationAST(config: UpdateMutationConfig): DocumentNode { - const { table } = config; - const { typeName, singularName } = getTableNames(table); - const mutationName = getUpdateMutationName(table); - const inputTypeName = `Update${typeName}Input`; - const scalarFields = getScalarFields(table); - - // Variable definitions - const variableDefinitions: VariableDefinitionNode[] = [ - t.variableDefinition({ - variable: t.variable({ name: 'input' }), - type: t.nonNullType({ type: t.namedType({ type: inputTypeName }) }), - }), - ]; - - // Mutation arguments - const args: ArgumentNode[] = [ - t.argument({ name: 'input', value: t.variable({ name: 'input' }) }), - ]; - - // Field selections - const fieldSelections = createFieldSelections(scalarFields); - - return t.document({ - definitions: [ - t.operationDefinition({ - operation: 'mutation', - name: `${ucFirst(mutationName)}Mutation`, - variableDefinitions, - selectionSet: t.selectionSet({ - selections: [ - t.field({ - name: mutationName, - args, - selectionSet: t.selectionSet({ - selections: [ - t.field({ - name: singularName, - selectionSet: t.selectionSet({ selections: fieldSelections }), - }), - ], - }), - }), - ], - }), - }), - ], - }); -} - -// ============================================================================ -// Delete mutation builder -// ============================================================================ - -export interface DeleteMutationConfig { - table: CleanTable; -} - -/** - * Build a delete mutation AST for a table - */ -export function buildDeleteMutationAST(config: DeleteMutationConfig): DocumentNode { - const { table } = config; - const { typeName } = getTableNames(table); - const mutationName = getDeleteMutationName(table); - const inputTypeName = `Delete${typeName}Input`; - - // Variable definitions - const variableDefinitions: VariableDefinitionNode[] = [ - t.variableDefinition({ - variable: t.variable({ name: 'input' }), - type: t.nonNullType({ type: t.namedType({ type: inputTypeName }) }), - }), - ]; - - // Mutation arguments - const args: ArgumentNode[] = [ - t.argument({ name: 'input', value: t.variable({ name: 'input' }) }), - ]; - - return t.document({ - definitions: [ - t.operationDefinition({ - operation: 'mutation', - name: `${ucFirst(mutationName)}Mutation`, - variableDefinitions, - selectionSet: t.selectionSet({ - selections: [ - t.field({ - name: mutationName, - args, - selectionSet: t.selectionSet({ - selections: [ - t.field({ name: 'clientMutationId' }), - ], - }), - }), - ], - }), - }), - ], - }); -} - -// ============================================================================ -// Print utilities -// ============================================================================ - -/** - * Print AST to GraphQL string - */ -export function printGraphQL(ast: DocumentNode): string { - return print(ast); -} diff --git a/graphql/codegen/src/core/codegen/hooks-ast.ts b/graphql/codegen/src/core/codegen/hooks-ast.ts new file mode 100644 index 000000000..1d60d7e38 --- /dev/null +++ b/graphql/codegen/src/core/codegen/hooks-ast.ts @@ -0,0 +1,815 @@ +/** + * Shared Babel AST helpers for React Query hook generators + * + * Provides reusable AST-building functions for the common patterns + * used across queries.ts, mutations.ts, custom-queries.ts, and custom-mutations.ts. + */ +import * as t from '@babel/types'; + +import type { CleanArgument } from '../../types/schema'; +import { commentBlock, generateCode } from './babel-ast'; +import { scalarToTsType } from './type-resolver'; +import { getGeneratedFileHeader } from './utils'; + +// ============================================================================ +// Import helpers +// ============================================================================ + +export function createImportDeclaration( + moduleSpecifier: string, + namedImports: string[], + typeOnly: boolean = false, +): t.ImportDeclaration { + const specifiers = namedImports.map((name) => + t.importSpecifier(t.identifier(name), t.identifier(name)), + ); + const decl = t.importDeclaration( + specifiers, + t.stringLiteral(moduleSpecifier), + ); + decl.importKind = typeOnly ? 'type' : 'value'; + return decl; +} + +export function createTypeReExport( + names: string[], + moduleSpecifier: string, +): t.ExportNamedDeclaration { + const specifiers = names.map((name) => + t.exportSpecifier(t.identifier(name), t.identifier(name)), + ); + const decl = t.exportNamedDeclaration( + null, + specifiers, + t.stringLiteral(moduleSpecifier), + ); + decl.exportKind = 'type'; + return decl; +} + +// ============================================================================ +// Type reference helpers +// ============================================================================ + +export function typeRef(name: string, params?: t.TSType[]): t.TSTypeReference { + return t.tsTypeReference( + t.identifier(name), + params ? t.tsTypeParameterInstantiation(params) : undefined, + ); +} + +export function sRef(): t.TSTypeReference { + return typeRef('S'); +} + +export function typeofRef(name: string): t.TSTypeQuery { + return t.tsTypeQuery(t.identifier(name)); +} + +export function stringLiteralType(value: string): t.TSLiteralType { + return t.tsLiteralType(t.stringLiteral(value)); +} + +// ============================================================================ +// Complex type builders +// ============================================================================ + +export function inferSelectResultType( + entityTypeName: string, + selectType: t.TSType, +): t.TSTypeReference { + return typeRef('InferSelectResult', [typeRef(entityTypeName), selectType]); +} + +export function connectionResultType( + entityTypeName: string, + selectType: t.TSType, +): t.TSTypeReference { + return typeRef('ConnectionResult', [ + inferSelectResultType(entityTypeName, selectType), + ]); +} + +export function typeLiteralWithProps( + props: Array<{ name: string; type: t.TSType; optional?: boolean }>, +): t.TSTypeLiteral { + return t.tsTypeLiteral( + props.map((p) => { + const prop = t.tsPropertySignature( + t.identifier(p.name), + t.tsTypeAnnotation(p.type), + ); + if (p.optional) { + prop.optional = true; + } + return prop; + }), + ); +} + +export function queryResultType( + queryName: string, + innerType: t.TSType, +): t.TSTypeLiteral { + return typeLiteralWithProps([{ name: queryName, type: innerType }]); +} + +export function listQueryResultType( + queryName: string, + entityTypeName: string, + selectType: t.TSType, +): t.TSTypeLiteral { + return queryResultType( + queryName, + connectionResultType(entityTypeName, selectType), + ); +} + +export function singleQueryResultType( + queryName: string, + entityTypeName: string, + selectType: t.TSType, + nullable: boolean = true, +): t.TSTypeLiteral { + const resultType = inferSelectResultType(entityTypeName, selectType); + const innerType = nullable + ? t.tsUnionType([resultType, t.tsNullKeyword()]) + : resultType; + return queryResultType(queryName, innerType); +} + +export function mutationResultType( + mutationName: string, + entityField: string, + entityTypeName: string, + selectType: t.TSType, +): t.TSTypeLiteral { + return queryResultType( + mutationName, + typeLiteralWithProps([ + { + name: entityField, + type: inferSelectResultType(entityTypeName, selectType), + }, + ]), + ); +} + +export function omitType( + baseType: t.TSType, + keys: string[], +): t.TSTypeReference { + const keyType = + keys.length === 1 + ? stringLiteralType(keys[0]) + : t.tsUnionType(keys.map(stringLiteralType)); + return typeRef('Omit', [baseType, keyType]); +} + +export function listSelectionConfigType( + selectType: t.TSType, + filterTypeName: string, + orderByTypeName: string, +): t.TSTypeReference { + return typeRef('ListSelectionConfig', [ + selectType, + typeRef(filterTypeName), + typeRef(orderByTypeName), + ]); +} + +export function selectionConfigType(selectType: t.TSType): t.TSTypeReference { + return typeRef('SelectionConfig', [selectType]); +} + +export function strictSelectType( + selectType: t.TSType, + shapeTypeName: string, +): t.TSTypeReference { + return typeRef('StrictSelect', [selectType, typeRef(shapeTypeName)]); +} + +export function withFieldsSelectionType( + selectType: t.TSType, + selectTypeName: string, +): t.TSIntersectionType { + return t.tsIntersectionType([ + typeLiteralWithProps([{ name: 'fields', type: selectType }]), + strictSelectType(selectType, selectTypeName), + ]); +} + +export function withFieldsListSelectionType( + selectType: t.TSType, + selectTypeName: string, + filterTypeName: string, + orderByTypeName: string, +): t.TSIntersectionType { + return t.tsIntersectionType([ + typeLiteralWithProps([{ name: 'fields', type: selectType }]), + omitType( + listSelectionConfigType(selectType, filterTypeName, orderByTypeName), + ['fields'], + ), + strictSelectType(selectType, selectTypeName), + ]); +} + +export function useQueryOptionsType( + queryDataType: t.TSType, + dataType: t.TSType, + extraProps?: t.TSType, +): t.TSType { + const base = omitType( + typeRef('UseQueryOptions', [queryDataType, typeRef('Error'), dataType]), + ['queryKey', 'queryFn'], + ); + if (extraProps) { + return t.tsIntersectionType([base, extraProps]); + } + return base; +} + +export function useQueryOptionsImplType(extraProps?: t.TSType): t.TSType { + const base = omitType( + typeRef('UseQueryOptions', [ + t.tsAnyKeyword(), + typeRef('Error'), + t.tsAnyKeyword(), + t.tsAnyKeyword(), + ]), + ['queryKey', 'queryFn'], + ); + if (extraProps) { + return t.tsIntersectionType([base, extraProps]); + } + return base; +} + +export function useMutationOptionsType( + resultType: t.TSType, + varType: t.TSType, +): t.TSTypeReference { + return omitType( + typeRef('UseMutationOptions', [resultType, typeRef('Error'), varType]), + ['mutationFn'], + ); +} + +export function useMutationResultType( + resultType: t.TSType, + varType: t.TSType, +): t.TSTypeReference { + return typeRef('UseMutationResult', [resultType, typeRef('Error'), varType]); +} + +// ============================================================================ +// Type parameter helpers +// ============================================================================ + +export function createSTypeParam( + constraintName: string, +): t.TSTypeParameterDeclaration { + const param = t.tsTypeParameter(typeRef(constraintName), null, 'S'); + return t.tsTypeParameterDeclaration([param]); +} + +export function createSAndTDataTypeParams( + constraintName: string, + defaultDataType: t.TSType, +): t.TSTypeParameterDeclaration { + const sParam = t.tsTypeParameter(typeRef(constraintName), null, 'S'); + const tDataParam = t.tsTypeParameter(null, defaultDataType, 'TData'); + return t.tsTypeParameterDeclaration([sParam, tDataParam]); +} + +export function createTDataTypeParam( + defaultType: t.TSType, +): t.TSTypeParameterDeclaration { + const param = t.tsTypeParameter(null, defaultType, 'TData'); + return t.tsTypeParameterDeclaration([param]); +} + +// ============================================================================ +// Function declaration helpers +// ============================================================================ + +export function createFunctionParam( + name: string, + typeAnnotation: t.TSType, + optional: boolean = false, +): t.Identifier { + const param = t.identifier(name); + param.typeAnnotation = t.tsTypeAnnotation(typeAnnotation); + param.optional = optional; + return param; +} + +export function exportDeclareFunction( + name: string, + typeParameters: t.TSTypeParameterDeclaration | null, + params: t.Identifier[], + returnType: t.TSType, +): t.ExportNamedDeclaration { + const func = t.tsDeclareFunction( + t.identifier(name), + typeParameters, + params, + t.tsTypeAnnotation(returnType), + ); + return t.exportNamedDeclaration(func); +} + +export function exportFunction( + name: string, + typeParameters: t.TSTypeParameterDeclaration | null, + params: t.Identifier[], + body: t.Statement[], + returnType?: t.TSType, +): t.ExportNamedDeclaration { + const func = t.functionDeclaration( + t.identifier(name), + params, + t.blockStatement(body), + ); + func.typeParameters = typeParameters; + if (returnType) { + func.returnType = t.tsTypeAnnotation(returnType); + } + return t.exportNamedDeclaration(func); +} + +export function exportAsyncFunction( + name: string, + typeParameters: t.TSTypeParameterDeclaration | null, + params: t.Identifier[], + body: t.Statement[], + returnType?: t.TSType, +): t.ExportNamedDeclaration { + const func = t.functionDeclaration( + t.identifier(name), + params, + t.blockStatement(body), + ); + func.async = true; + func.typeParameters = typeParameters; + if (returnType) { + func.returnType = t.tsTypeAnnotation(returnType); + } + return t.exportNamedDeclaration(func); +} + +export function exportAsyncDeclareFunction( + name: string, + typeParameters: t.TSTypeParameterDeclaration | null, + params: t.Identifier[], + returnType: t.TSType, +): t.ExportNamedDeclaration { + const func = t.tsDeclareFunction( + t.identifier(name), + typeParameters, + params, + t.tsTypeAnnotation(returnType), + ); + func.async = true; + return t.exportNamedDeclaration(func); +} + +// ============================================================================ +// Expression helpers +// ============================================================================ + +export function callExpr( + callee: string | t.Expression, + args: (t.Expression | t.SpreadElement)[], +): t.CallExpression { + const calleeExpr = typeof callee === 'string' ? t.identifier(callee) : callee; + return t.callExpression(calleeExpr, args); +} + +export function memberExpr(obj: string, prop: string): t.MemberExpression { + return t.memberExpression(t.identifier(obj), t.identifier(prop)); +} + +export function optionalMemberExpr( + obj: string, + prop: string, +): t.OptionalMemberExpression { + return t.optionalMemberExpression( + t.identifier(obj), + t.identifier(prop), + false, + true, + ); +} + +export function arrowFn( + params: t.Identifier[], + body: t.Expression | t.BlockStatement, +): t.ArrowFunctionExpression { + return t.arrowFunctionExpression(params, body); +} + +export function awaitExpr(expr: t.Expression): t.AwaitExpression { + return t.awaitExpression(expr); +} + +export function spreadObj(expr: t.Expression): t.SpreadElement { + return t.spreadElement(expr); +} + +export function objectProp( + key: string, + value: t.Expression, + shorthand: boolean = false, +): t.ObjectProperty { + return t.objectProperty(t.identifier(key), value, false, shorthand); +} + +export function shorthandProp(name: string): t.ObjectProperty { + return t.objectProperty(t.identifier(name), t.identifier(name), false, true); +} + +export function constDecl( + name: string, + init: t.Expression, +): t.VariableDeclaration { + return t.variableDeclaration('const', [ + t.variableDeclarator(t.identifier(name), init), + ]); +} + +export function asConstExpr(expr: t.Expression): t.TSAsExpression { + return t.tsAsExpression(expr, t.tsTypeReference(t.identifier('const'))); +} + +export function asTypeExpr( + expr: t.Expression, + typeName: string, +): t.TSAsExpression { + return t.tsAsExpression(expr, typeRef(typeName)); +} + +// ============================================================================ +// Statement helpers +// ============================================================================ + +export function voidStatement(name: string): t.ExpressionStatement { + return t.expressionStatement(t.unaryExpression('void', t.identifier(name))); +} + +export function returnUseQuery( + queryKeyExpr: t.Expression, + queryFnExpr: t.Expression, + extraProps?: Array, + enabledExpr?: t.Expression, +): t.ReturnStatement { + const props: Array = [ + objectProp('queryKey', queryKeyExpr), + objectProp('queryFn', queryFnExpr), + ]; + if (enabledExpr) { + props.push(objectProp('enabled', enabledExpr)); + } + if (extraProps) { + props.push(...extraProps); + } + return t.returnStatement(callExpr('useQuery', [t.objectExpression(props)])); +} + +export function returnUseMutation( + mutationFnExpr: t.Expression, + extraProps: Array, + mutationKeyExpr?: t.Expression, +): t.ReturnStatement { + const props: Array = []; + if (mutationKeyExpr) { + props.push(objectProp('mutationKey', mutationKeyExpr)); + } + props.push(objectProp('mutationFn', mutationFnExpr)); + props.push(...extraProps); + return t.returnStatement( + callExpr('useMutation', [t.objectExpression(props)]), + ); +} + +// ============================================================================ +// Destructuring helpers +// ============================================================================ + +export function destructureWithRest( + source: t.Expression, + keys: string[], + restName: string, +): t.VariableDeclaration { + const properties = keys.map((key) => + t.objectProperty(t.identifier(key), t.identifier(`_${key}`), false, false), + ); + const pattern = t.objectPattern([ + ...properties, + t.restElement(t.identifier(restName)), + ]); + return constDecl(restName, t.identifier('__placeholder__')); +} + +export function destructureParamsWithSelection( + restName: string, + extraKeys: string[] = [], +): t.VariableDeclaration { + const properties: (t.ObjectProperty | t.RestElement)[] = []; + for (const key of extraKeys) { + properties.push( + t.objectProperty(t.identifier(key), t.identifier(key), false, true), + ); + } + properties.push( + t.objectProperty( + t.identifier('selection'), + t.identifier('_selection'), + false, + false, + ), + ); + properties.push(t.restElement(t.identifier(restName))); + + const pattern = t.objectPattern(properties); + return t.variableDeclaration('const', [ + t.variableDeclarator( + pattern, + t.logicalExpression('??', t.identifier('params'), t.objectExpression([])), + ), + ]); +} + +export function destructureParamsWithSelectionAndScope( + restName: string, +): t.VariableDeclaration { + const pattern = t.objectPattern([ + t.objectProperty(t.identifier('scope'), t.identifier('scope'), false, true), + t.objectProperty( + t.identifier('selection'), + t.identifier('_selection'), + false, + false, + ), + t.restElement(t.identifier(restName)), + ]); + return t.variableDeclaration('const', [ + t.variableDeclarator( + pattern, + t.logicalExpression('??', t.identifier('params'), t.objectExpression([])), + ), + ]); +} + +// ============================================================================ +// JSDoc comment helpers +// ============================================================================ + +export function addJSDocComment(node: T, lines: string[]): T { + const text = + lines.length === 1 + ? `* ${lines[0]} ` + : `*\n${lines.map((line) => ` * ${line}`).join('\n')}\n `; + if (!node.leadingComments) { + node.leadingComments = []; + } + node.leadingComments.push(commentBlock(text)); + return node; +} + +export function addLineComment(node: T, text: string): T { + if (!node.leadingComments) { + node.leadingComments = []; + } + node.leadingComments.push({ + type: 'CommentLine', + value: ` ${text}`, + start: null, + end: null, + loc: null, + }); + return node; +} + +// ============================================================================ +// ORM client call builders +// ============================================================================ + +export function getClientCall( + modelName: string, + method: string, + args: t.Expression, +): t.CallExpression { + return t.callExpression( + t.memberExpression( + t.memberExpression(callExpr('getClient', []), t.identifier(modelName)), + t.identifier(method), + ), + [args], + ); +} + +export function getClientCallUnwrap( + modelName: string, + method: string, + args: t.Expression, +): t.CallExpression { + return t.callExpression( + t.memberExpression( + getClientCall(modelName, method, args), + t.identifier('unwrap'), + ), + [], + ); +} + +export function getClientCustomCall( + operationType: 'query' | 'mutation', + operationName: string, + args: t.Expression[], + optionsArg?: t.Expression, +): t.CallExpression { + const callArgs = optionsArg ? [...args, optionsArg] : args; + return t.callExpression( + t.memberExpression( + t.memberExpression( + callExpr('getClient', []), + t.identifier(operationType), + ), + t.identifier(operationName), + ), + callArgs, + ); +} + +export function getClientCustomCallUnwrap( + operationType: 'query' | 'mutation', + operationName: string, + args: t.Expression[], + optionsArg?: t.Expression, +): t.CallExpression { + return t.callExpression( + t.memberExpression( + getClientCustomCall(operationType, operationName, args, optionsArg), + t.identifier('unwrap'), + ), + [], + ); +} + +// ============================================================================ +// Select/args expression builders +// ============================================================================ + +export function buildFindManyCallExpr( + singularName: string, + argsIdent: string, +): t.CallExpression { + return getClientCallUnwrap(singularName, 'findMany', t.identifier(argsIdent)); +} + +export function buildFindOneCallExpr( + singularName: string, + pkFieldName: string, + argsIdent: string, + paramsIdent: string = 'params', +): t.CallExpression { + return getClientCallUnwrap( + singularName, + 'findOne', + t.objectExpression([ + objectProp( + pkFieldName, + t.memberExpression( + t.identifier(paramsIdent), + t.identifier(pkFieldName), + ), + ), + objectProp( + 'select', + t.memberExpression(t.identifier(argsIdent), t.identifier('select')), + ), + ]), + ); +} + +// ============================================================================ +// Code generation +// ============================================================================ + +export function generateHookFileCode( + headerDescription: string, + statements: t.Statement[], +): string { + const header = getGeneratedFileHeader(headerDescription); + const code = generateCode(statements); + return header + '\n\n' + code + '\n'; +} + +// ============================================================================ +// Scope type helper +// ============================================================================ + +export function scopeTypeLiteral(scopeTypeName: string): t.TSTypeLiteral { + return typeLiteralWithProps([ + { + name: 'scope', + type: typeRef(scopeTypeName), + optional: true, + }, + ]); +} + +// ============================================================================ +// Type conversion helpers (GraphQL -> AST) +// ============================================================================ + +export function wrapInferSelectResultType( + typeRefNode: CleanArgument['type'], + payloadTypeName: string, + selectType: t.TSType, +): t.TSType { + if (typeRefNode.kind === 'NON_NULL' && typeRefNode.ofType) { + return wrapInferSelectResultType( + typeRefNode.ofType as CleanArgument['type'], + payloadTypeName, + selectType, + ); + } + if (typeRefNode.kind === 'LIST' && typeRefNode.ofType) { + return t.tsArrayType( + wrapInferSelectResultType( + typeRefNode.ofType as CleanArgument['type'], + payloadTypeName, + selectType, + ), + ); + } + return inferSelectResultType(payloadTypeName, selectType); +} + +export function typeRefToTsTypeAST( + typeRefNode: CleanArgument['type'], +): t.TSType { + if (typeRefNode.kind === 'NON_NULL' && typeRefNode.ofType) { + return typeRefToTsTypeAST(typeRefNode.ofType as CleanArgument['type']); + } + if (typeRefNode.kind === 'LIST' && typeRefNode.ofType) { + return t.tsArrayType( + typeRefToTsTypeAST(typeRefNode.ofType as CleanArgument['type']), + ); + } + if (typeRefNode.kind === 'SCALAR') { + const tsType = scalarToTsType(typeRefNode.name ?? 'unknown'); + if (tsType === 'string') return t.tsStringKeyword(); + if (tsType === 'number') return t.tsNumberKeyword(); + if (tsType === 'boolean') return t.tsBooleanKeyword(); + return t.tsUnknownKeyword(); + } + return typeRef(typeRefNode.name ?? 'unknown'); +} + +export function buildSelectionArgsCall( + selectTypeName: string, +): t.VariableDeclaration { + const call = t.callExpression(t.identifier('buildSelectionArgs'), [ + t.memberExpression(t.identifier('params'), t.identifier('selection')), + ]); + // @ts-ignore - Babel types support typeParameters on CallExpression for TS + call.typeParameters = t.tsTypeParameterInstantiation([ + typeRef(selectTypeName), + ]); + return constDecl('args', call); +} + +export function buildListSelectionArgsCall( + selectTypeName: string, + filterTypeName: string, + orderByTypeName: string, +): t.VariableDeclaration { + const call = t.callExpression(t.identifier('buildListSelectionArgs'), [ + t.memberExpression(t.identifier('params'), t.identifier('selection')), + ]); + // @ts-ignore - Babel types support typeParameters on CallExpression for TS + call.typeParameters = t.tsTypeParameterInstantiation([ + typeRef(selectTypeName), + typeRef(filterTypeName), + typeRef(orderByTypeName), + ]); + return constDecl('args', call); +} + +export function customSelectResultTypeLiteral( + opName: string, + returnType: CleanArgument['type'], + payloadTypeName: string, + selectType: t.TSType, +): t.TSTypeLiteral { + return typeLiteralWithProps([ + { + name: opName, + type: wrapInferSelectResultType(returnType, payloadTypeName, selectType), + }, + ]); +} diff --git a/graphql/codegen/src/core/codegen/index.ts b/graphql/codegen/src/core/codegen/index.ts index 407e10527..312dda394 100644 --- a/graphql/codegen/src/core/codegen/index.ts +++ b/graphql/codegen/src/core/codegen/index.ts @@ -2,52 +2,52 @@ * Code generation orchestrator * * Coordinates all code generators to produce the complete SDK output. + * Hooks delegate to ORM model methods - types are imported from ORM's input-types.ts. * * Output structure: * generated/ * index.ts - Main barrel export - * client.ts - GraphQL client with configure() and execute() - * types.ts - Entity interfaces and filter types + * client.ts - ORM client wrapper (configure/getClient) * queries/ * index.ts - Query hooks barrel - * useCarsQuery.ts - List query hook (table-based) - * useCarQuery.ts - Single item query hook (table-based) - * useCurrentUserQuery.ts - Custom query hook + * useCarsQuery.ts - List query hook -> ORM findMany + * useCarQuery.ts - Single item query hook -> ORM findOne + * useCurrentUserQuery.ts - Custom query hook -> ORM query.xxx * ... * mutations/ * index.ts - Mutation hooks barrel - * useCreateCarMutation.ts - Table-based CRUD - * useUpdateCarMutation.ts - * useDeleteCarMutation.ts - * useLoginMutation.ts - Custom mutation - * useRegisterMutation.ts + * useCreateCarMutation.ts - -> ORM create + * useUpdateCarMutation.ts - -> ORM update + * useDeleteCarMutation.ts - -> ORM delete + * useLoginMutation.ts - Custom mutation -> ORM mutation.xxx * ... */ import type { - CleanTable, + GraphQLSDKConfigTarget, + QueryKeyConfig, +} from '../../types/config'; +import { DEFAULT_QUERY_KEY_CONFIG } from '../../types/config'; +import type { CleanOperation, + CleanTable, TypeRegistry, } from '../../types/schema'; -import type { GraphQLSDKConfigTarget, QueryKeyConfig } from '../../types/config'; -import { DEFAULT_QUERY_KEY_CONFIG } from '../../types/config'; - -import { generateClientFile } from './client'; -import { generateTypesFile } from './types'; -import { generateSchemaTypesFile } from './schema-types-generator'; -import { generateAllQueryHooks } from './queries'; -import { generateAllMutationHooks } from './mutations'; -import { generateAllCustomQueryHooks } from './custom-queries'; -import { generateAllCustomMutationHooks } from './custom-mutations'; -import { generateQueryKeysFile } from './query-keys'; -import { generateMutationKeysFile } from './mutation-keys'; -import { generateInvalidationFile } from './invalidation'; import { - generateQueriesBarrel, - generateMutationsBarrel, - generateMainBarrel, - generateCustomQueriesBarrel, generateCustomMutationsBarrel, + generateCustomQueriesBarrel, + generateMainBarrel, + generateMutationsBarrel, + generateQueriesBarrel, } from './barrel'; +import { generateClientFile } from './client'; +import { generateAllCustomMutationHooks } from './custom-mutations'; +import { generateAllCustomQueryHooks } from './custom-queries'; +import { generateInvalidationFile } from './invalidation'; +import { generateMutationKeysFile } from './mutation-keys'; +import { generateAllMutationHooks } from './mutations'; +import { generateAllQueryHooks } from './queries'; +import { generateQueryKeysFile } from './query-keys'; +import { generateSelectionFile } from './selection'; import { getTableNames } from './utils'; // ============================================================================ @@ -102,7 +102,7 @@ export interface GenerateOptions { */ export function generateAllFiles( tables: CleanTable[], - config: GraphQLSDKConfigTarget + config: GraphQLSDKConfigTarget, ): GenerateResult { return generate({ tables, config }); } @@ -114,75 +114,37 @@ export function generateAllFiles( * (they're expected to exist in the shared types directory). */ export function generate(options: GenerateOptions): GenerateResult { - const { tables, customOperations, config, sharedTypesPath } = options; + const { tables, customOperations, config } = options; const files: GeneratedFile[] = []; // Extract codegen options - const maxDepth = config.codegen.maxFieldDepth; const skipQueryField = config.codegen.skipQueryField; const reactQueryEnabled = config.reactQuery; // Query key configuration (use defaults if not provided) - const queryKeyConfig: QueryKeyConfig = config.queryKeys ?? DEFAULT_QUERY_KEY_CONFIG; + const queryKeyConfig: QueryKeyConfig = + config.queryKeys ?? DEFAULT_QUERY_KEY_CONFIG; const useCentralizedKeys = queryKeyConfig.generateScopedKeys; const hasRelationships = Object.keys(queryKeyConfig.relationships).length > 0; - // 1. Generate client.ts + // 1. Generate client.ts (ORM client wrapper) files.push({ path: 'client.ts', - content: generateClientFile({ - browserCompatible: config.browserCompatible ?? true, - }), + content: generateClientFile(), + }); + + // 1b. Generate selection.ts (shared selection adapters for hooks) + files.push({ + path: 'selection.ts', + content: generateSelectionFile(), }); // Collect table type names for import path resolution const tableTypeNames = new Set(tables.map((t) => getTableNames(t).typeName)); - // When using shared types, skip generating types.ts and schema-types.ts - // They're already generated in the shared directory - let hasSchemaTypes = false; - let generatedEnumNames: string[] = []; - - if (sharedTypesPath) { - // Using shared types - check if schema-types would be generated - if (customOperations && customOperations.typeRegistry) { - const schemaTypesResult = generateSchemaTypesFile({ - typeRegistry: customOperations.typeRegistry, - tableTypeNames, - }); - if (schemaTypesResult.content.split('\n').length > 10) { - hasSchemaTypes = true; - generatedEnumNames = schemaTypesResult.generatedEnums || []; - } - } - } else { - // 2. Generate schema-types.ts for custom operations (if any) - // NOTE: This must come BEFORE types.ts so that types.ts can import enum types - if (customOperations && customOperations.typeRegistry) { - const schemaTypesResult = generateSchemaTypesFile({ - typeRegistry: customOperations.typeRegistry, - tableTypeNames, - }); - - // Only include if there's meaningful content - if (schemaTypesResult.content.split('\n').length > 10) { - files.push({ - path: 'schema-types.ts', - content: schemaTypesResult.content, - }); - hasSchemaTypes = true; - generatedEnumNames = schemaTypesResult.generatedEnums || []; - } - } - - // 3. Generate types.ts (can now import enums from schema-types) - files.push({ - path: 'types.ts', - content: generateTypesFile(tables, { - enumsFromSchemaTypes: generatedEnumNames, - }), - }); - } + // NOTE: types.ts and schema-types.ts are no longer generated here. + // Hooks now import types directly from the ORM's input-types.ts, + // which serves as the single source of truth for all types. // 3b. Generate centralized query keys (query-keys.ts) let hasQueryKeys = false; @@ -251,7 +213,6 @@ export function generate(options: GenerateOptions): GenerateResult { customQueryHooks = generateAllCustomQueryHooks({ operations: customOperations.queries, typeRegistry: customOperations.typeRegistry, - maxDepth, skipQueryField, reactQueryEnabled, tableTypeNames, @@ -273,7 +234,7 @@ export function generate(options: GenerateOptions): GenerateResult { customQueryHooks.length > 0 ? generateCustomQueriesBarrel( tables, - customQueryHooks.map((h) => h.operationName) + customQueryHooks.map((h) => h.operationName), ) : generateQueriesBarrel(tables), }); @@ -281,10 +242,7 @@ export function generate(options: GenerateOptions): GenerateResult { // 6. Generate table-based mutation hooks (mutations/*.ts) const mutationHooks = generateAllMutationHooks(tables, { reactQueryEnabled, - enumsFromSchemaTypes: generatedEnumNames, useCentralizedKeys, - hasRelationships, - tableTypeNames, }); for (const hook of mutationHooks) { files.push({ @@ -303,7 +261,6 @@ export function generate(options: GenerateOptions): GenerateResult { customMutationHooks = generateAllCustomMutationHooks({ operations: customOperations.mutations, typeRegistry: customOperations.typeRegistry, - maxDepth, skipQueryField, reactQueryEnabled, tableTypeNames, @@ -329,17 +286,17 @@ export function generate(options: GenerateOptions): GenerateResult { customMutationHooks.length > 0 ? generateCustomMutationsBarrel( tables, - customMutationHooks.map((h) => h.operationName) + customMutationHooks.map((h) => h.operationName), ) : generateMutationsBarrel(tables), }); } - // 9. Generate main index.ts barrel (with schema-types if present) + // 9. Generate main index.ts barrel + // No longer includes types.ts or schema-types.ts - hooks import from ORM directly files.push({ path: 'index.ts', content: generateMainBarrel(tables, { - hasSchemaTypes, hasMutations, hasQueryKeys, hasMutationKeys, @@ -364,34 +321,33 @@ export function generate(options: GenerateOptions): GenerateResult { // Re-exports for convenience // ============================================================================ -export { generateClientFile } from './client'; -export { generateTypesFile } from './types'; export { - generateAllQueryHooks, - generateListQueryHook, - generateSingleQueryHook, -} from './queries'; + generateCustomMutationsBarrel, + generateCustomQueriesBarrel, + generateMainBarrel, + generateMutationsBarrel, + generateQueriesBarrel, +} from './barrel'; +export { generateClientFile } from './client'; export { - generateAllMutationHooks, - generateCreateMutationHook, - generateUpdateMutationHook, - generateDeleteMutationHook, -} from './mutations'; + generateAllCustomMutationHooks, + generateCustomMutationHook, +} from './custom-mutations'; export { generateAllCustomQueryHooks, generateCustomQueryHook, } from './custom-queries'; +export { generateInvalidationFile } from './invalidation'; +export { generateMutationKeysFile } from './mutation-keys'; export { - generateAllCustomMutationHooks, - generateCustomMutationHook, -} from './custom-mutations'; + generateAllMutationHooks, + generateCreateMutationHook, + generateDeleteMutationHook, + generateUpdateMutationHook, +} from './mutations'; export { - generateQueriesBarrel, - generateMutationsBarrel, - generateMainBarrel, - generateCustomQueriesBarrel, - generateCustomMutationsBarrel, -} from './barrel'; + generateAllQueryHooks, + generateListQueryHook, + generateSingleQueryHook, +} from './queries'; export { generateQueryKeysFile } from './query-keys'; -export { generateMutationKeysFile } from './mutation-keys'; -export { generateInvalidationFile } from './invalidation'; diff --git a/graphql/codegen/src/core/codegen/invalidation.ts b/graphql/codegen/src/core/codegen/invalidation.ts index 96247303e..c2932af32 100644 --- a/graphql/codegen/src/core/codegen/invalidation.ts +++ b/graphql/codegen/src/core/codegen/invalidation.ts @@ -4,17 +4,23 @@ * Generates type-safe cache invalidation utilities with cascade support * for parent-child entity relationships. */ -import type { CleanTable } from '../../types/schema'; -import type { QueryKeyConfig, EntityRelationship } from '../../types/config'; -import { getTableNames, getGeneratedFileHeader, ucFirst, lcFirst } from './utils'; import * as t from '@babel/types'; + +import type { EntityRelationship, QueryKeyConfig } from '../../types/config'; +import type { CleanTable } from '../../types/schema'; import { - generateCode, addJSDocComment, + addLineComment, asConst, + generateCode, typedParam, - addLineComment, } from './babel-ast'; +import { + getGeneratedFileHeader, + getTableNames, + lcFirst, + ucFirst, +} from './utils'; export interface InvalidationGeneratorOptions { tables: CleanTable[]; @@ -30,7 +36,7 @@ export interface GeneratedInvalidationFile { * Build a map of parent -> children for cascade invalidation */ function buildChildrenMap( - relationships: Record + relationships: Record, ): Map { const childrenMap = new Map(); @@ -50,7 +56,7 @@ function buildChildrenMap( */ function getAllDescendants( entity: string, - childrenMap: Map + childrenMap: Map, ): string[] { const descendants: string[] = []; const queue = [entity.toLowerCase()]; @@ -74,7 +80,7 @@ function buildEntityInvalidateProperty( table: CleanTable, relationships: Record, childrenMap: Map, - allTables: CleanTable[] + allTables: CleanTable[], ): t.ObjectProperty { const { typeName, singularName } = getTableNames(table); const entityKey = typeName.toLowerCase(); @@ -88,20 +94,31 @@ function buildEntityInvalidateProperty( const innerProperties: t.ObjectProperty[] = []; // Helper to create QueryClient type reference - const queryClientTypeRef = () => t.tsTypeReference(t.identifier('QueryClient')); - const stringOrNumberType = () => t.tsUnionType([t.tsStringKeyword(), t.tsNumberKeyword()]); + const queryClientTypeRef = () => + t.tsTypeReference(t.identifier('QueryClient')); + const stringOrNumberType = () => + t.tsUnionType([t.tsStringKeyword(), t.tsNumberKeyword()]); // Helper to create queryClient.invalidateQueries({ queryKey: ... }) const invalidateCall = (queryKeyExpr: t.Expression) => t.callExpression( - t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), - [t.objectExpression([t.objectProperty(t.identifier('queryKey'), queryKeyExpr)])] + t.memberExpression( + t.identifier('queryClient'), + t.identifier('invalidateQueries'), + ), + [ + t.objectExpression([ + t.objectProperty(t.identifier('queryKey'), queryKeyExpr), + ]), + ], ); // all property const allArrowFn = t.arrowFunctionExpression( [typedParam('queryClient', queryClientTypeRef())], - invalidateCall(t.memberExpression(t.identifier(keysName), t.identifier('all'))) + invalidateCall( + t.memberExpression(t.identifier(keysName), t.identifier('all')), + ), ); const allProp = t.objectProperty(t.identifier('all'), allArrowFn); addJSDocComment(allProp, [`Invalidate all ${singularName} queries`]); @@ -111,15 +128,19 @@ function buildEntityInvalidateProperty( let listsProp: t.ObjectProperty; if (hasParent) { const scopeTypeName = `${typeName}Scope`; - const scopeParam = typedParam('scope', t.tsTypeReference(t.identifier(scopeTypeName)), true); + const scopeParam = typedParam( + 'scope', + t.tsTypeReference(t.identifier(scopeTypeName)), + true, + ); const listsArrowFn = t.arrowFunctionExpression( [typedParam('queryClient', queryClientTypeRef()), scopeParam], invalidateCall( t.callExpression( t.memberExpression(t.identifier(keysName), t.identifier('lists')), - [t.identifier('scope')] - ) - ) + [t.identifier('scope')], + ), + ), ); listsProp = t.objectProperty(t.identifier('lists'), listsArrowFn); } else { @@ -128,9 +149,9 @@ function buildEntityInvalidateProperty( invalidateCall( t.callExpression( t.memberExpression(t.identifier(keysName), t.identifier('lists')), - [] - ) - ) + [], + ), + ), ); listsProp = t.objectProperty(t.identifier('lists'), listsArrowFn); } @@ -141,26 +162,37 @@ function buildEntityInvalidateProperty( let detailProp: t.ObjectProperty; if (hasParent) { const scopeTypeName = `${typeName}Scope`; - const scopeParam = typedParam('scope', t.tsTypeReference(t.identifier(scopeTypeName)), true); + const scopeParam = typedParam( + 'scope', + t.tsTypeReference(t.identifier(scopeTypeName)), + true, + ); const detailArrowFn = t.arrowFunctionExpression( - [typedParam('queryClient', queryClientTypeRef()), typedParam('id', stringOrNumberType()), scopeParam], + [ + typedParam('queryClient', queryClientTypeRef()), + typedParam('id', stringOrNumberType()), + scopeParam, + ], invalidateCall( t.callExpression( t.memberExpression(t.identifier(keysName), t.identifier('detail')), - [t.identifier('id'), t.identifier('scope')] - ) - ) + [t.identifier('id'), t.identifier('scope')], + ), + ), ); detailProp = t.objectProperty(t.identifier('detail'), detailArrowFn); } else { const detailArrowFn = t.arrowFunctionExpression( - [typedParam('queryClient', queryClientTypeRef()), typedParam('id', stringOrNumberType())], + [ + typedParam('queryClient', queryClientTypeRef()), + typedParam('id', stringOrNumberType()), + ], invalidateCall( t.callExpression( t.memberExpression(t.identifier(keysName), t.identifier('detail')), - [t.identifier('id')] - ) - ) + [t.identifier('id')], + ), + ), ); detailProp = t.objectProperty(t.identifier('detail'), detailArrowFn); } @@ -176,9 +208,9 @@ function buildEntityInvalidateProperty( invalidateCall( t.callExpression( t.memberExpression(t.identifier(keysName), t.identifier('detail')), - [t.identifier('id')] - ) - ) + [t.identifier('id')], + ), + ), ); addLineComment(selfDetailStmt, `Invalidate this ${singularName}`); cascadeStatements.push(selfDetailStmt); @@ -188,17 +220,17 @@ function buildEntityInvalidateProperty( invalidateCall( t.callExpression( t.memberExpression(t.identifier(keysName), t.identifier('lists')), - [] - ) - ) - ) + [], + ), + ), + ), ); // Comment: Cascade to child entities let firstCascade = true; for (const descendant of descendants) { const descendantTable = allTables.find( - (tbl) => getTableNames(tbl).typeName.toLowerCase() === descendant + (tbl) => getTableNames(tbl).typeName.toLowerCase() === descendant, ); if (descendantTable) { const { typeName: descTypeName } = getTableNames(descendantTable); @@ -218,16 +250,22 @@ function buildEntityInvalidateProperty( cascadeStmt = t.expressionStatement( invalidateCall( t.callExpression( - t.memberExpression(t.identifier(descKeysName), t.identifier(`by${ucFirst(typeName)}`)), - [t.identifier('id')] - ) - ) + t.memberExpression( + t.identifier(descKeysName), + t.identifier(`by${ucFirst(typeName)}`), + ), + [t.identifier('id')], + ), + ), ); } else { cascadeStmt = t.expressionStatement( invalidateCall( - t.memberExpression(t.identifier(descKeysName), t.identifier('all')) - ) + t.memberExpression( + t.identifier(descKeysName), + t.identifier('all'), + ), + ), ); } @@ -241,10 +279,16 @@ function buildEntityInvalidateProperty( } const withChildrenArrowFn = t.arrowFunctionExpression( - [typedParam('queryClient', queryClientTypeRef()), typedParam('id', stringOrNumberType())], - t.blockStatement(cascadeStatements) + [ + typedParam('queryClient', queryClientTypeRef()), + typedParam('id', stringOrNumberType()), + ], + t.blockStatement(cascadeStatements), + ); + const withChildrenProp = t.objectProperty( + t.identifier('withChildren'), + withChildrenArrowFn, ); - const withChildrenProp = t.objectProperty(t.identifier('withChildren'), withChildrenArrowFn); addJSDocComment(withChildrenProp, [ `Invalidate ${singularName} and all child entities`, `Cascades to: ${descendants.join(', ')}`, @@ -252,7 +296,10 @@ function buildEntityInvalidateProperty( innerProperties.push(withChildrenProp); } - const entityProp = t.objectProperty(t.identifier(singularName), t.objectExpression(innerProperties)); + const entityProp = t.objectProperty( + t.identifier(singularName), + t.objectExpression(innerProperties), + ); addJSDocComment(entityProp, [`Invalidate ${singularName} queries`]); return entityProp; } @@ -262,54 +309,80 @@ function buildEntityInvalidateProperty( */ function buildEntityRemoveProperty( table: CleanTable, - relationships: Record + relationships: Record, ): t.ObjectProperty { const { typeName, singularName } = getTableNames(table); const keysName = `${lcFirst(typeName)}Keys`; const relationship = relationships[typeName.toLowerCase()]; // Helper types - const queryClientTypeRef = () => t.tsTypeReference(t.identifier('QueryClient')); - const stringOrNumberType = () => t.tsUnionType([t.tsStringKeyword(), t.tsNumberKeyword()]); + const queryClientTypeRef = () => + t.tsTypeReference(t.identifier('QueryClient')); + const stringOrNumberType = () => + t.tsUnionType([t.tsStringKeyword(), t.tsNumberKeyword()]); // Helper to create queryClient.removeQueries({ queryKey: ... }) const removeCall = (queryKeyExpr: t.Expression) => t.callExpression( - t.memberExpression(t.identifier('queryClient'), t.identifier('removeQueries')), - [t.objectExpression([t.objectProperty(t.identifier('queryKey'), queryKeyExpr)])] + t.memberExpression( + t.identifier('queryClient'), + t.identifier('removeQueries'), + ), + [ + t.objectExpression([ + t.objectProperty(t.identifier('queryKey'), queryKeyExpr), + ]), + ], ); let removeProp: t.ObjectProperty; if (relationship) { const scopeTypeName = `${typeName}Scope`; - const scopeParam = typedParam('scope', t.tsTypeReference(t.identifier(scopeTypeName)), true); + const scopeParam = typedParam( + 'scope', + t.tsTypeReference(t.identifier(scopeTypeName)), + true, + ); const removeArrowFn = t.arrowFunctionExpression( - [typedParam('queryClient', queryClientTypeRef()), typedParam('id', stringOrNumberType()), scopeParam], + [ + typedParam('queryClient', queryClientTypeRef()), + typedParam('id', stringOrNumberType()), + scopeParam, + ], t.blockStatement([ t.expressionStatement( removeCall( t.callExpression( - t.memberExpression(t.identifier(keysName), t.identifier('detail')), - [t.identifier('id'), t.identifier('scope')] - ) - ) - ) - ]) + t.memberExpression( + t.identifier(keysName), + t.identifier('detail'), + ), + [t.identifier('id'), t.identifier('scope')], + ), + ), + ), + ]), ); removeProp = t.objectProperty(t.identifier(singularName), removeArrowFn); } else { const removeArrowFn = t.arrowFunctionExpression( - [typedParam('queryClient', queryClientTypeRef()), typedParam('id', stringOrNumberType())], + [ + typedParam('queryClient', queryClientTypeRef()), + typedParam('id', stringOrNumberType()), + ], t.blockStatement([ t.expressionStatement( removeCall( t.callExpression( - t.memberExpression(t.identifier(keysName), t.identifier('detail')), - [t.identifier('id')] - ) - ) - ) - ]) + t.memberExpression( + t.identifier(keysName), + t.identifier('detail'), + ), + [t.identifier('id')], + ), + ), + ), + ]), ); removeProp = t.objectProperty(t.identifier(singularName), removeArrowFn); } @@ -322,7 +395,7 @@ function buildEntityRemoveProperty( * Generate the complete invalidation.ts file */ export function generateInvalidationFile( - options: InvalidationGeneratorOptions + options: InvalidationGeneratorOptions, ): GeneratedInvalidationFile { const { tables, config } = options; const { relationships, generateCascadeHelpers } = config; @@ -333,8 +406,13 @@ export function generateInvalidationFile( // Import QueryClient type const queryClientImport = t.importDeclaration( - [t.importSpecifier(t.identifier('QueryClient'), t.identifier('QueryClient'))], - t.stringLiteral('@tanstack/react-query') + [ + t.importSpecifier( + t.identifier('QueryClient'), + t.identifier('QueryClient'), + ), + ], + t.stringLiteral('@tanstack/react-query'), ); queryClientImport.importKind = 'type'; statements.push(queryClientImport); @@ -347,9 +425,11 @@ export function generateInvalidationFile( } statements.push( t.importDeclaration( - keyImports.map(name => t.importSpecifier(t.identifier(name), t.identifier(name))), - t.stringLiteral('./query-keys') - ) + keyImports.map((name) => + t.importSpecifier(t.identifier(name), t.identifier(name)), + ), + t.stringLiteral('./query-keys'), + ), ); // Import scope types if needed @@ -362,8 +442,10 @@ export function generateInvalidationFile( } if (scopeTypes.length > 0) { const scopeImport = t.importDeclaration( - scopeTypes.map(name => t.importSpecifier(t.identifier(name), t.identifier(name))), - t.stringLiteral('./query-keys') + scopeTypes.map((name) => + t.importSpecifier(t.identifier(name), t.identifier(name)), + ), + t.stringLiteral('./query-keys'), ); scopeImport.importKind = 'type'; statements.push(scopeImport); @@ -372,16 +454,18 @@ export function generateInvalidationFile( // Generate invalidate object const invalidateProperties: t.ObjectProperty[] = []; for (const table of tables) { - invalidateProperties.push(buildEntityInvalidateProperty(table, relationships, childrenMap, tables)); + invalidateProperties.push( + buildEntityInvalidateProperty(table, relationships, childrenMap, tables), + ); } const invalidateDecl = t.exportNamedDeclaration( t.variableDeclaration('const', [ t.variableDeclarator( t.identifier('invalidate'), - asConst(t.objectExpression(invalidateProperties)) - ) - ]) + asConst(t.objectExpression(invalidateProperties)), + ), + ]), ); // Build JSDoc for invalidate @@ -402,7 +486,9 @@ export function generateInvalidationFile( if (generateCascadeHelpers && Object.keys(relationships).length > 0) { invalidateDocLines.push(''); invalidateDocLines.push('// Cascade invalidate (entity + all children)'); - invalidateDocLines.push('invalidate.database.withChildren(queryClient, databaseId);'); + invalidateDocLines.push( + 'invalidate.database.withChildren(queryClient, databaseId);', + ); } invalidateDocLines.push('```'); addJSDocComment(invalidateDecl, invalidateDocLines); @@ -418,9 +504,9 @@ export function generateInvalidationFile( t.variableDeclaration('const', [ t.variableDeclarator( t.identifier('remove'), - asConst(t.objectExpression(removeProperties)) - ) - ]) + asConst(t.objectExpression(removeProperties)), + ), + ]), ); addJSDocComment(removeDecl, [ 'Remove queries from cache (for delete operations)', @@ -459,7 +545,10 @@ ${description} const line = codeLines[i]; // Detect invalidation section (after imports) - if (!addedInvalidationSection && line.includes('* Type-safe query invalidation helpers')) { + if ( + !addedInvalidationSection && + line.includes('* Type-safe query invalidation helpers') + ) { content += `// ============================================================================ // Invalidation Helpers // ============================================================================ diff --git a/graphql/codegen/src/core/codegen/mutation-keys.ts b/graphql/codegen/src/core/codegen/mutation-keys.ts index 431d84fe3..b9ca8df09 100644 --- a/graphql/codegen/src/core/codegen/mutation-keys.ts +++ b/graphql/codegen/src/core/codegen/mutation-keys.ts @@ -7,17 +7,18 @@ * - Mutation deduplication * - Tracking mutation state with useIsMutating */ -import type { CleanTable, CleanOperation } from '../../types/schema'; -import type { QueryKeyConfig, EntityRelationship } from '../../types/config'; -import { getTableNames, getGeneratedFileHeader, lcFirst } from './utils'; import * as t from '@babel/types'; + +import type { EntityRelationship, QueryKeyConfig } from '../../types/config'; +import type { CleanOperation, CleanTable } from '../../types/schema'; import { - generateCode, addJSDocComment, asConst, constArray, + generateCode, typedParam, } from './babel-ast'; +import { getGeneratedFileHeader, getTableNames, lcFirst } from './utils'; export interface MutationKeyGeneratorOptions { tables: CleanTable[]; @@ -35,7 +36,7 @@ export interface GeneratedMutationKeysFile { */ function generateEntityMutationKeysDeclaration( table: CleanTable, - relationships: Record + relationships: Record, ): t.ExportNamedDeclaration { const { typeName, singularName } = getTableNames(table); const entityKey = typeName.toLowerCase(); @@ -48,7 +49,7 @@ function generateEntityMutationKeysDeclaration( // all property const allProp = t.objectProperty( t.identifier('all'), - constArray([t.stringLiteral('mutation'), t.stringLiteral(entityKey)]) + constArray([t.stringLiteral('mutation'), t.stringLiteral(entityKey)]), ); addJSDocComment(allProp, [`All ${singularName} mutation keys`]); properties.push(allProp); @@ -73,16 +74,16 @@ function generateEntityMutationKeysDeclaration( t.identifier(relationship.foreignKey), t.identifier(relationship.foreignKey), false, - true - ) + true, + ), ]), ]), constArray([ t.stringLiteral('mutation'), t.stringLiteral(entityKey), t.stringLiteral('create'), - ]) - ) + ]), + ), ); createProp = t.objectProperty(t.identifier('create'), arrowFn); @@ -93,7 +94,7 @@ function generateEntityMutationKeysDeclaration( t.stringLiteral('mutation'), t.stringLiteral(entityKey), t.stringLiteral('create'), - ]) + ]), ); createProp = t.objectProperty(t.identifier('create'), arrowFn); @@ -103,13 +104,18 @@ function generateEntityMutationKeysDeclaration( // update property const updateArrowFn = t.arrowFunctionExpression( - [typedParam('id', t.tsUnionType([t.tsStringKeyword(), t.tsNumberKeyword()]))], + [ + typedParam( + 'id', + t.tsUnionType([t.tsStringKeyword(), t.tsNumberKeyword()]), + ), + ], constArray([ t.stringLiteral('mutation'), t.stringLiteral(entityKey), t.stringLiteral('update'), t.identifier('id'), - ]) + ]), ); const updateProp = t.objectProperty(t.identifier('update'), updateArrowFn); addJSDocComment(updateProp, [`Update ${singularName} mutation key`]); @@ -117,13 +123,18 @@ function generateEntityMutationKeysDeclaration( // delete property const deleteArrowFn = t.arrowFunctionExpression( - [typedParam('id', t.tsUnionType([t.tsStringKeyword(), t.tsNumberKeyword()]))], + [ + typedParam( + 'id', + t.tsUnionType([t.tsStringKeyword(), t.tsNumberKeyword()]), + ), + ], constArray([ t.stringLiteral('mutation'), t.stringLiteral(entityKey), t.stringLiteral('delete'), t.identifier('id'), - ]) + ]), ); const deleteProp = t.objectProperty(t.identifier('delete'), deleteArrowFn); addJSDocComment(deleteProp, [`Delete ${singularName} mutation key`]); @@ -133,9 +144,9 @@ function generateEntityMutationKeysDeclaration( t.variableDeclaration('const', [ t.variableDeclarator( t.identifier(keysName), - asConst(t.objectExpression(properties)) - ) - ]) + asConst(t.objectExpression(properties)), + ), + ]), ); } @@ -143,7 +154,7 @@ function generateEntityMutationKeysDeclaration( * Generate custom mutation keys declaration */ function generateCustomMutationKeysDeclaration( - operations: CleanOperation[] + operations: CleanOperation[], ): t.ExportNamedDeclaration | null { if (operations.length === 0) return null; @@ -168,15 +179,15 @@ function generateCustomMutationKeysDeclaration( t.stringLiteral(op.name), t.identifier('identifier'), ]), - constArray([t.stringLiteral('mutation'), t.stringLiteral(op.name)]) - ) + constArray([t.stringLiteral('mutation'), t.stringLiteral(op.name)]), + ), ); prop = t.objectProperty(t.identifier(op.name), arrowFn); } else { const arrowFn = t.arrowFunctionExpression( [], - constArray([t.stringLiteral('mutation'), t.stringLiteral(op.name)]) + constArray([t.stringLiteral('mutation'), t.stringLiteral(op.name)]), ); prop = t.objectProperty(t.identifier(op.name), arrowFn); @@ -190,9 +201,9 @@ function generateCustomMutationKeysDeclaration( t.variableDeclaration('const', [ t.variableDeclarator( t.identifier('customMutationKeys'), - asConst(t.objectExpression(properties)) - ) - ]) + asConst(t.objectExpression(properties)), + ), + ]), ); } @@ -201,7 +212,7 @@ function generateCustomMutationKeysDeclaration( */ function generateUnifiedMutationStoreDeclaration( tables: CleanTable[], - hasCustomMutations: boolean + hasCustomMutations: boolean, ): t.ExportNamedDeclaration { const properties: t.ObjectProperty[] = []; @@ -209,13 +220,16 @@ function generateUnifiedMutationStoreDeclaration( const { typeName } = getTableNames(table); const keysName = `${lcFirst(typeName)}MutationKeys`; properties.push( - t.objectProperty(t.identifier(lcFirst(typeName)), t.identifier(keysName)) + t.objectProperty(t.identifier(lcFirst(typeName)), t.identifier(keysName)), ); } if (hasCustomMutations) { properties.push( - t.objectProperty(t.identifier('custom'), t.identifier('customMutationKeys')) + t.objectProperty( + t.identifier('custom'), + t.identifier('customMutationKeys'), + ), ); } @@ -223,9 +237,9 @@ function generateUnifiedMutationStoreDeclaration( t.variableDeclaration('const', [ t.variableDeclarator( t.identifier('mutationKeys'), - asConst(t.objectExpression(properties)) - ) - ]) + asConst(t.objectExpression(properties)), + ), + ]), ); addJSDocComment(decl, [ @@ -253,7 +267,7 @@ function generateUnifiedMutationStoreDeclaration( * Generate the complete mutation-keys.ts file */ export function generateMutationKeysFile( - options: MutationKeyGeneratorOptions + options: MutationKeyGeneratorOptions, ): GeneratedMutationKeysFile { const { tables, customMutations, config } = options; const { relationships } = config; @@ -262,18 +276,28 @@ export function generateMutationKeysFile( // Generate entity mutation keys for (const table of tables) { - statements.push(generateEntityMutationKeysDeclaration(table, relationships)); + statements.push( + generateEntityMutationKeysDeclaration(table, relationships), + ); } // Generate custom mutation keys - const mutationOperations = customMutations.filter((op) => op.kind === 'mutation'); - const customKeysDecl = generateCustomMutationKeysDeclaration(mutationOperations); + const mutationOperations = customMutations.filter( + (op) => op.kind === 'mutation', + ); + const customKeysDecl = + generateCustomMutationKeysDeclaration(mutationOperations); if (customKeysDecl) { statements.push(customKeysDecl); } // Generate unified store - statements.push(generateUnifiedMutationStoreDeclaration(tables, mutationOperations.length > 0)); + statements.push( + generateUnifiedMutationStoreDeclaration( + tables, + mutationOperations.length > 0, + ), + ); // Generate code from AST const code = generateCode(statements); @@ -309,7 +333,10 @@ ${description} const line = codeLines[i]; // Detect custom mutation keys section - if (!addedCustomSection && line.startsWith('export const customMutationKeys')) { + if ( + !addedCustomSection && + line.startsWith('export const customMutationKeys') + ) { content += ` // ============================================================================ // Custom Mutation Keys diff --git a/graphql/codegen/src/core/codegen/mutations.ts b/graphql/codegen/src/core/codegen/mutations.ts index 0a3a75227..d99b95acb 100644 --- a/graphql/codegen/src/core/codegen/mutations.ts +++ b/graphql/codegen/src/core/codegen/mutations.ts @@ -1,51 +1,59 @@ /** - * Mutation hook generators using Babel AST-based code generation + * Mutation hook generators - delegates to ORM model methods (Babel AST-based) * * Output structure: * mutations/ - * useCreateCarMutation.ts - * useUpdateCarMutation.ts - * useDeleteCarMutation.ts + * useCreateCarMutation.ts -> ORM create + * useUpdateCarMutation.ts -> ORM update + * useDeleteCarMutation.ts -> ORM delete */ -import type { CleanTable } from '../../types/schema'; import * as t from '@babel/types'; -import { generateCode, addJSDocComment, typedParam, createTypedCallExpression } from './babel-ast'; + +import type { CleanTable } from '../../types/schema'; import { - buildCreateMutationAST, - buildUpdateMutationAST, - buildDeleteMutationAST, - printGraphQL, -} from './gql-ast'; + addJSDocComment, + buildSelectionArgsCall, + callExpr, + constDecl, + createFunctionParam, + createImportDeclaration, + createSTypeParam, + createTypeReExport, + destructureParamsWithSelection, + exportDeclareFunction, + exportFunction, + generateHookFileCode, + getClientCallUnwrap, + inferSelectResultType, + objectProp, + omitType, + returnUseMutation, + selectionConfigType, + shorthandProp, + spreadObj, + sRef, + typeRef, + typeLiteralWithProps, + useMutationOptionsType, + useMutationResultType, + voidStatement, +} from './hooks-ast'; import { - getTableNames, - getCreateMutationHookName, - getUpdateMutationHookName, - getDeleteMutationHookName, getCreateMutationFileName, - getUpdateMutationFileName, - getDeleteMutationFileName, + getCreateMutationHookName, getCreateMutationName, - getUpdateMutationName, + getDeleteMutationFileName, + getDeleteMutationHookName, getDeleteMutationName, - getScalarFields, getPrimaryKeyInfo, - fieldTypeToTs, - ucFirst, + getTableNames, + getUpdateMutationFileName, + getUpdateMutationHookName, + getUpdateMutationName, + hasValidPrimaryKey, lcFirst, - getGeneratedFileHeader, } from './utils'; -function isAutoGeneratedField(fieldName: string, pkFieldNames: Set): boolean { - const name = fieldName.toLowerCase(); - if (pkFieldNames.has(fieldName)) return true; - const timestampPatterns = [ - 'createdat', 'created_at', 'createddate', 'created_date', - 'updatedat', 'updated_at', 'updateddate', 'updated_date', - 'deletedat', 'deleted_at', - ]; - return timestampPatterns.includes(name); -} - export interface GeneratedMutationFile { fileName: string; content: string; @@ -53,884 +61,765 @@ export interface GeneratedMutationFile { export interface MutationGeneratorOptions { reactQueryEnabled?: boolean; - enumsFromSchemaTypes?: string[]; useCentralizedKeys?: boolean; - hasRelationships?: boolean; - /** All table type names for determining which types to import from types.ts vs schema-types.ts */ - tableTypeNames?: Set; +} + +function buildMutationResultType( + mutationName: string, + singularName: string, + relationTypeName: string, + selectType: t.TSType, +): t.TSTypeLiteral { + return typeLiteralWithProps([ + { + name: mutationName, + type: typeLiteralWithProps([ + { + name: singularName, + type: inferSelectResultType(relationTypeName, selectType), + }, + ]), + }, + ]); +} + +function buildFieldsSelectionType( + s: t.TSType, + selectTypeName: string, +): t.TSParenthesizedType { + return t.tsParenthesizedType( + t.tsIntersectionType([ + t.tsTypeLiteral([ + t.tsPropertySignature(t.identifier('fields'), t.tsTypeAnnotation(s)), + ]), + typeRef('StrictSelect', [s, typeRef(selectTypeName)]), + ]), + ); } export function generateCreateMutationHook( table: CleanTable, - options: MutationGeneratorOptions = {} + options: MutationGeneratorOptions = {}, ): GeneratedMutationFile | null { - const { - reactQueryEnabled = true, - enumsFromSchemaTypes = [], - useCentralizedKeys = true, - hasRelationships = false, - tableTypeNames = new Set(), - } = options; - - if (!reactQueryEnabled) { - return null; - } + const { reactQueryEnabled = true, useCentralizedKeys = true } = options; + + if (!reactQueryEnabled) return null; - const enumSet = new Set(enumsFromSchemaTypes); const { typeName, singularName } = getTableNames(table); const hookName = getCreateMutationHookName(table); + const mutationName = getCreateMutationName(table); const keysName = `${lcFirst(typeName)}Keys`; const mutationKeysName = `${lcFirst(typeName)}MutationKeys`; - const scopeTypeName = `${typeName}Scope`; - const mutationName = getCreateMutationName(table); - const scalarFields = getScalarFields(table); - - const pkFieldNames = new Set(getPrimaryKeyInfo(table).map((pk) => pk.name)); - - const usedEnums = new Set(); - const usedTableTypes = new Set(); - for (const field of scalarFields) { - const cleanType = field.type.gqlType.replace(/!/g, ''); - if (enumSet.has(cleanType)) { - usedEnums.add(cleanType); - } else if (tableTypeNames.has(cleanType) && cleanType !== typeName) { - // Track table types used in scalar fields (excluding the main type which is already imported) - usedTableTypes.add(cleanType); - } - } - - const mutationAST = buildCreateMutationAST({ table }); - const mutationDocument = printGraphQL(mutationAST); + const selectTypeName = `${typeName}Select`; + const relationTypeName = `${typeName}WithRelations`; + const createInputTypeName = `Create${typeName}Input`; const statements: t.Statement[] = []; - const reactQueryImport = t.importDeclaration( - [ - t.importSpecifier(t.identifier('useMutation'), t.identifier('useMutation')), - t.importSpecifier(t.identifier('useQueryClient'), t.identifier('useQueryClient')), - ], - t.stringLiteral('@tanstack/react-query') - ); - statements.push(reactQueryImport); - - const reactQueryTypeImport = t.importDeclaration( - [t.importSpecifier(t.identifier('UseMutationOptions'), t.identifier('UseMutationOptions'))], - t.stringLiteral('@tanstack/react-query') + // Imports + statements.push( + createImportDeclaration('@tanstack/react-query', [ + 'useMutation', + 'useQueryClient', + ]), + ); + statements.push( + createImportDeclaration( + '@tanstack/react-query', + ['UseMutationOptions', 'UseMutationResult'], + true, + ), ); - reactQueryTypeImport.importKind = 'type'; - statements.push(reactQueryTypeImport); - - const clientImport = t.importDeclaration( - [t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], - t.stringLiteral('../client') + statements.push(createImportDeclaration('../client', ['getClient'])); + statements.push( + createImportDeclaration('../selection', ['buildSelectionArgs']), ); - statements.push(clientImport); - - // Import the main type and any other table types used in scalar fields - const allTypesToImport = [typeName, ...Array.from(usedTableTypes)].sort(); - const typesImport = t.importDeclaration( - allTypesToImport.map((t_) => t.importSpecifier(t.identifier(t_), t.identifier(t_))), - t.stringLiteral('../types') + statements.push( + createImportDeclaration('../selection', ['SelectionConfig'], true), ); - typesImport.importKind = 'type'; - statements.push(typesImport); - - if (usedEnums.size > 0) { - const enumImport = t.importDeclaration( - Array.from(usedEnums).sort().map((e) => t.importSpecifier(t.identifier(e), t.identifier(e))), - t.stringLiteral('../schema-types') - ); - enumImport.importKind = 'type'; - statements.push(enumImport); - } if (useCentralizedKeys) { - const queryKeyImport = t.importDeclaration( - [t.importSpecifier(t.identifier(keysName), t.identifier(keysName))], - t.stringLiteral('../query-keys') - ); - statements.push(queryKeyImport); - if (hasRelationships) { - const scopeTypeImport = t.importDeclaration( - [t.importSpecifier(t.identifier(scopeTypeName), t.identifier(scopeTypeName))], - t.stringLiteral('../query-keys') - ); - scopeTypeImport.importKind = 'type'; - statements.push(scopeTypeImport); - } - const mutationKeyImport = t.importDeclaration( - [t.importSpecifier(t.identifier(mutationKeysName), t.identifier(mutationKeysName))], - t.stringLiteral('../mutation-keys') + statements.push(createImportDeclaration('../query-keys', [keysName])); + statements.push( + createImportDeclaration('../mutation-keys', [mutationKeysName]), ); - statements.push(mutationKeyImport); } - const reExportDecl = t.exportNamedDeclaration( - null, - [t.exportSpecifier(t.identifier(typeName), t.identifier(typeName))], - t.stringLiteral('../types') - ); - reExportDecl.exportKind = 'type'; - statements.push(reExportDecl); - - const mutationDocConst = t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier(`${mutationName}MutationDocument`), - t.templateLiteral( - [t.templateElement({ raw: '\n' + mutationDocument, cooked: '\n' + mutationDocument }, true)], - [] - ) + statements.push( + createImportDeclaration( + '../../orm/input-types', + [selectTypeName, relationTypeName, createInputTypeName], + true, ), - ]); - statements.push(t.exportNamedDeclaration(mutationDocConst)); - - const inputFields = scalarFields - .filter((f) => !isAutoGeneratedField(f.name, pkFieldNames)) - .map((f) => { - const prop = t.tsPropertySignature( - t.identifier(f.name), - t.tsTypeAnnotation( - t.tsUnionType([ - t.tsTypeReference(t.identifier(fieldTypeToTs(f.type))), - t.tsNullKeyword(), - ]) - ) - ); - prop.optional = true; - return prop; - }); - - const createInputInterface = t.tsInterfaceDeclaration( - t.identifier(`${typeName}CreateInput`), - null, - null, - t.tsInterfaceBody(inputFields) - ); - addJSDocComment(createInputInterface, [`Input type for creating a ${typeName}`]); - statements.push(createInputInterface); - - const variablesInterfaceBody = t.tsInterfaceBody([ - t.tsPropertySignature( - t.identifier('input'), - t.tsTypeAnnotation( - t.tsTypeLiteral([ - t.tsPropertySignature( - t.identifier(lcFirst(typeName)), - t.tsTypeAnnotation(t.tsTypeReference(t.identifier(`${typeName}CreateInput`))) - ), - ]) - ) + ); + statements.push( + createImportDeclaration( + '../../orm/select-types', + ['InferSelectResult', 'StrictSelect'], + true, ), - ]); - const variablesInterface = t.tsInterfaceDeclaration( - t.identifier(`${ucFirst(mutationName)}MutationVariables`), - null, - null, - variablesInterfaceBody ); - statements.push(t.exportNamedDeclaration(variablesInterface)); - const resultInterfaceBody = t.tsInterfaceBody([ - t.tsPropertySignature( - t.identifier(mutationName), - t.tsTypeAnnotation( - t.tsTypeLiteral([ - t.tsPropertySignature( - t.identifier(singularName), - t.tsTypeAnnotation(t.tsTypeReference(t.identifier(typeName))) - ), - ]) - ) + // Re-exports + statements.push( + createTypeReExport( + [selectTypeName, relationTypeName, createInputTypeName], + '../../orm/input-types', ), - ]); - const resultInterface = t.tsInterfaceDeclaration( - t.identifier(`${ucFirst(mutationName)}MutationResult`), - null, - null, - resultInterfaceBody - ); - statements.push(t.exportNamedDeclaration(resultInterface)); - - const hookBodyStatements: t.Statement[] = []; - hookBodyStatements.push( - t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier('queryClient'), - t.callExpression(t.identifier('useQueryClient'), []) - ), - ]) - ); - - const mutationOptions: (t.ObjectProperty | t.SpreadElement)[] = []; - if (useCentralizedKeys) { - mutationOptions.push( - t.objectProperty( - t.identifier('mutationKey'), - t.callExpression( - t.memberExpression(t.identifier(mutationKeysName), t.identifier('create')), - [] - ) - ) - ); - } - mutationOptions.push( - t.objectProperty( - t.identifier('mutationFn'), - t.arrowFunctionExpression( - [typedParam('variables', t.tsTypeReference(t.identifier(`${ucFirst(mutationName)}MutationVariables`)))], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(`${mutationName}MutationDocument`), t.identifier('variables')], - [ - t.tsTypeReference(t.identifier(`${ucFirst(mutationName)}MutationResult`)), - t.tsTypeReference(t.identifier(`${ucFirst(mutationName)}MutationVariables`)), - ] - ) - ) - ) - ); - - const invalidateQueryKey = useCentralizedKeys - ? t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('lists')), []) - : t.arrayExpression([t.stringLiteral(typeName.toLowerCase()), t.stringLiteral('list')]); - - mutationOptions.push( - t.objectProperty( - t.identifier('onSuccess'), - t.arrowFunctionExpression( - [], - t.blockStatement([ - t.expressionStatement( - t.callExpression( - t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), - [t.objectExpression([t.objectProperty(t.identifier('queryKey'), invalidateQueryKey)])] - ) - ), - ]) - ) - ) ); - mutationOptions.push(t.spreadElement(t.identifier('options'))); - hookBodyStatements.push( - t.returnStatement( - t.callExpression(t.identifier('useMutation'), [t.objectExpression(mutationOptions)]) - ) + // Variable type: CreateTypeName['singularName'] + const createVarType = t.tsIndexedAccessType( + typeRef(createInputTypeName), + t.tsLiteralType(t.stringLiteral(singularName)), ); - const optionsTypeStr = `Omit, 'mutationFn'>`; - const optionsParam = t.identifier('options'); - optionsParam.optional = true; - optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(optionsTypeStr))); + const resultType = (sel: t.TSType) => + buildMutationResultType(mutationName, singularName, relationTypeName, sel); - const hookFunc = t.functionDeclaration( - t.identifier(hookName), - [optionsParam], - t.blockStatement(hookBodyStatements) + // Overload 1: with fields + const o1ParamType = t.tsIntersectionType([ + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(buildFieldsSelectionType(sRef(), selectTypeName)), + ), + ]), + useMutationOptionsType(resultType(sRef()), createVarType), + ]); + const o1 = exportDeclareFunction( + hookName, + createSTypeParam(selectTypeName), + [createFunctionParam('params', o1ParamType)], + useMutationResultType(resultType(sRef()), createVarType), ); - const hookExport = t.exportNamedDeclaration(hookFunc); - addJSDocComment(hookExport, [ + addJSDocComment(o1, [ `Mutation hook for creating a ${typeName}`, '', '@example', '```tsx', - `const { mutate, isPending } = ${hookName}();`, - '', - 'mutate({', - ' input: {', - ` ${lcFirst(typeName)}: {`, - ' // ... fields', - ' },', - ' },', + `const { mutate, isPending } = ${hookName}({`, + ' selection: { fields: { id: true, name: true } },', '});', + '', + "mutate({ name: 'New item' });", '```', ]); - statements.push(hookExport); + statements.push(o1); + + // Implementation + const implSelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName))), + ); + const implParamType = t.tsIntersectionType([ + t.tsTypeLiteral([implSelProp]), + omitType( + typeRef('UseMutationOptions', [ + t.tsAnyKeyword(), + typeRef('Error'), + createVarType, + ]), + ['mutationFn'], + ), + ]); + + const body: t.Statement[] = []; + body.push(buildSelectionArgsCall(selectTypeName)); + body.push(destructureParamsWithSelection('mutationOptions')); + body.push(voidStatement('_selection')); + body.push(constDecl('queryClient', callExpr('useQueryClient', []))); + + const mutationKeyExpr = useCentralizedKeys + ? callExpr( + t.memberExpression( + t.identifier(mutationKeysName), + t.identifier('create'), + ), + [], + ) + : undefined; + + // mutationFn: (data: CreateInput['singular']) => getClient().singular.create({ data, select: ... }).unwrap() + const dataParam = createFunctionParam('data', createVarType); + const mutationFnExpr = t.arrowFunctionExpression( + [dataParam], + getClientCallUnwrap( + singularName, + 'create', + t.objectExpression([ + shorthandProp('data'), + objectProp( + 'select', + t.memberExpression(t.identifier('args'), t.identifier('select')), + ), + ]), + ), + ); + + // onSuccess: invalidate lists + const listKeyExpr = useCentralizedKeys + ? callExpr( + t.memberExpression(t.identifier(keysName), t.identifier('lists')), + [], + ) + : t.arrayExpression([ + t.stringLiteral(typeName.toLowerCase()), + t.stringLiteral('list'), + ]); + + const onSuccessFn = t.arrowFunctionExpression( + [], + t.blockStatement([ + t.expressionStatement( + callExpr( + t.memberExpression( + t.identifier('queryClient'), + t.identifier('invalidateQueries'), + ), + [t.objectExpression([objectProp('queryKey', listKeyExpr)])], + ), + ), + ]), + ); - const code = generateCode(statements); - const content = getGeneratedFileHeader(`Create mutation hook for ${typeName}`) + '\n\n' + code; + body.push( + returnUseMutation( + mutationFnExpr, + [ + objectProp('onSuccess', onSuccessFn), + spreadObj(t.identifier('mutationOptions')), + ], + mutationKeyExpr, + ), + ); + + statements.push( + exportFunction( + hookName, + null, + [createFunctionParam('params', implParamType)], + body, + ), + ); return { fileName: getCreateMutationFileName(table), - content, + content: generateHookFileCode( + `Create mutation hook for ${typeName}`, + statements, + ), }; } export function generateUpdateMutationHook( table: CleanTable, - options: MutationGeneratorOptions = {} + options: MutationGeneratorOptions = {}, ): GeneratedMutationFile | null { - const { - reactQueryEnabled = true, - enumsFromSchemaTypes = [], - useCentralizedKeys = true, - hasRelationships = false, - tableTypeNames = new Set(), - } = options; - - if (!reactQueryEnabled) { - return null; - } + const { reactQueryEnabled = true, useCentralizedKeys = true } = options; - if (table.query?.update === null) { - return null; - } + if (!reactQueryEnabled) return null; + if (table.query?.update === null) return null; + if (!hasValidPrimaryKey(table)) return null; - const enumSet = new Set(enumsFromSchemaTypes); const { typeName, singularName } = getTableNames(table); const hookName = getUpdateMutationHookName(table); const mutationName = getUpdateMutationName(table); - const scalarFields = getScalarFields(table); const keysName = `${lcFirst(typeName)}Keys`; const mutationKeysName = `${lcFirst(typeName)}MutationKeys`; - const scopeTypeName = `${typeName}Scope`; + const selectTypeName = `${typeName}Select`; + const relationTypeName = `${typeName}WithRelations`; + const patchTypeName = `${typeName}Patch`; const pkFields = getPrimaryKeyInfo(table); const pkField = pkFields[0]; - const pkFieldNames = new Set(pkFields.map((pk) => pk.name)); - - const usedEnums = new Set(); - const usedTableTypes = new Set(); - for (const field of scalarFields) { - const cleanType = field.type.gqlType.replace(/!/g, ''); - if (enumSet.has(cleanType)) { - usedEnums.add(cleanType); - } else if (tableTypeNames.has(cleanType) && cleanType !== typeName) { - usedTableTypes.add(cleanType); - } - } - const mutationAST = buildUpdateMutationAST({ table }); - const mutationDocument = printGraphQL(mutationAST); + const pkTsType = + pkField.tsType === 'string' ? t.tsStringKeyword() : t.tsNumberKeyword(); const statements: t.Statement[] = []; - const reactQueryImport = t.importDeclaration( - [ - t.importSpecifier(t.identifier('useMutation'), t.identifier('useMutation')), - t.importSpecifier(t.identifier('useQueryClient'), t.identifier('useQueryClient')), - ], - t.stringLiteral('@tanstack/react-query') - ); - statements.push(reactQueryImport); - - const reactQueryTypeImport = t.importDeclaration( - [t.importSpecifier(t.identifier('UseMutationOptions'), t.identifier('UseMutationOptions'))], - t.stringLiteral('@tanstack/react-query') + // Imports + statements.push( + createImportDeclaration('@tanstack/react-query', [ + 'useMutation', + 'useQueryClient', + ]), + ); + statements.push( + createImportDeclaration( + '@tanstack/react-query', + ['UseMutationOptions', 'UseMutationResult'], + true, + ), ); - reactQueryTypeImport.importKind = 'type'; - statements.push(reactQueryTypeImport); - - const clientImport = t.importDeclaration( - [t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], - t.stringLiteral('../client') + statements.push(createImportDeclaration('../client', ['getClient'])); + statements.push( + createImportDeclaration('../selection', ['buildSelectionArgs']), ); - statements.push(clientImport); - - // Import the main type and any other table types used in scalar fields - const allTypesToImportUpdate = [typeName, ...Array.from(usedTableTypes)].sort(); - const typesImport = t.importDeclaration( - allTypesToImportUpdate.map((t_) => t.importSpecifier(t.identifier(t_), t.identifier(t_))), - t.stringLiteral('../types') + statements.push( + createImportDeclaration('../selection', ['SelectionConfig'], true), ); - typesImport.importKind = 'type'; - statements.push(typesImport); - - if (usedEnums.size > 0) { - const enumImport = t.importDeclaration( - Array.from(usedEnums).sort().map((e) => t.importSpecifier(t.identifier(e), t.identifier(e))), - t.stringLiteral('../schema-types') - ); - enumImport.importKind = 'type'; - statements.push(enumImport); - } if (useCentralizedKeys) { - const queryKeyImport = t.importDeclaration( - [t.importSpecifier(t.identifier(keysName), t.identifier(keysName))], - t.stringLiteral('../query-keys') + statements.push(createImportDeclaration('../query-keys', [keysName])); + statements.push( + createImportDeclaration('../mutation-keys', [mutationKeysName]), ); - statements.push(queryKeyImport); - if (hasRelationships) { - const scopeTypeImport = t.importDeclaration( - [t.importSpecifier(t.identifier(scopeTypeName), t.identifier(scopeTypeName))], - t.stringLiteral('../query-keys') - ); - scopeTypeImport.importKind = 'type'; - statements.push(scopeTypeImport); - } - const mutationKeyImport = t.importDeclaration( - [t.importSpecifier(t.identifier(mutationKeysName), t.identifier(mutationKeysName))], - t.stringLiteral('../mutation-keys') - ); - statements.push(mutationKeyImport); } - const reExportDecl = t.exportNamedDeclaration( - null, - [t.exportSpecifier(t.identifier(typeName), t.identifier(typeName))], - t.stringLiteral('../types') + statements.push( + createImportDeclaration( + '../../orm/input-types', + [selectTypeName, relationTypeName, patchTypeName], + true, + ), ); - reExportDecl.exportKind = 'type'; - statements.push(reExportDecl); - - const mutationDocConst = t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier(`${mutationName}MutationDocument`), - t.templateLiteral( - [t.templateElement({ raw: '\n' + mutationDocument, cooked: '\n' + mutationDocument }, true)], - [] - ) + statements.push( + createImportDeclaration( + '../../orm/select-types', + ['InferSelectResult', 'StrictSelect'], + true, ), - ]); - statements.push(t.exportNamedDeclaration(mutationDocConst)); - - const patchFields = scalarFields - .filter((f) => !pkFieldNames.has(f.name)) - .map((f) => { - const prop = t.tsPropertySignature( - t.identifier(f.name), - t.tsTypeAnnotation( - t.tsUnionType([ - t.tsTypeReference(t.identifier(fieldTypeToTs(f.type))), - t.tsNullKeyword(), - ]) - ) - ); - prop.optional = true; - return prop; - }); - - const patchInterface = t.tsInterfaceDeclaration( - t.identifier(`${typeName}Patch`), - null, - null, - t.tsInterfaceBody(patchFields) - ); - addJSDocComment(patchInterface, [`Patch type for updating a ${typeName} - all fields optional`]); - statements.push(patchInterface); - - const pkTypeAnnotation = - pkField.tsType === 'string' - ? t.tsStringKeyword() - : pkField.tsType === 'number' - ? t.tsNumberKeyword() - : t.tsTypeReference(t.identifier(pkField.tsType)); - - const variablesInterfaceBody = t.tsInterfaceBody([ - t.tsPropertySignature( - t.identifier('input'), - t.tsTypeAnnotation( - t.tsTypeLiteral([ - t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkTypeAnnotation)), - t.tsPropertySignature( - t.identifier('patch'), - t.tsTypeAnnotation(t.tsTypeReference(t.identifier(`${typeName}Patch`))) - ), - ]) - ) + ); + + // Re-exports + statements.push( + createTypeReExport( + [selectTypeName, relationTypeName, patchTypeName], + '../../orm/input-types', ), - ]); - const variablesInterface = t.tsInterfaceDeclaration( - t.identifier(`${ucFirst(mutationName)}MutationVariables`), - null, - null, - variablesInterfaceBody ); - statements.push(t.exportNamedDeclaration(variablesInterface)); - const resultInterfaceBody = t.tsInterfaceBody([ + // Variable type: { pkField: type; patch: PatchType } + const updateVarType = t.tsTypeLiteral([ t.tsPropertySignature( - t.identifier(mutationName), - t.tsTypeAnnotation( - t.tsTypeLiteral([ - t.tsPropertySignature( - t.identifier(singularName), - t.tsTypeAnnotation(t.tsTypeReference(t.identifier(typeName))) - ), - ]) - ) + t.identifier(pkField.name), + t.tsTypeAnnotation(pkTsType), + ), + t.tsPropertySignature( + t.identifier('patch'), + t.tsTypeAnnotation(typeRef(patchTypeName)), ), ]); - const resultInterface = t.tsInterfaceDeclaration( - t.identifier(`${ucFirst(mutationName)}MutationResult`), - null, - null, - resultInterfaceBody - ); - statements.push(t.exportNamedDeclaration(resultInterface)); - - const hookBodyStatements: t.Statement[] = []; - hookBodyStatements.push( - t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier('queryClient'), - t.callExpression(t.identifier('useQueryClient'), []) + + const resultType = (sel: t.TSType) => + buildMutationResultType(mutationName, singularName, relationTypeName, sel); + + // Overload 1: with fields + const o1ParamType = t.tsIntersectionType([ + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(buildFieldsSelectionType(sRef(), selectTypeName)), ), - ]) + ]), + useMutationOptionsType(resultType(sRef()), updateVarType), + ]); + const o1 = exportDeclareFunction( + hookName, + createSTypeParam(selectTypeName), + [createFunctionParam('params', o1ParamType)], + useMutationResultType(resultType(sRef()), updateVarType), ); + addJSDocComment(o1, [ + `Mutation hook for updating a ${typeName}`, + '', + '@example', + '```tsx', + `const { mutate, isPending } = ${hookName}({`, + ' selection: { fields: { id: true, name: true } },', + '});', + '', + `mutate({ ${pkField.name}: 'value-here', patch: { name: 'Updated' } });`, + '```', + ]); + statements.push(o1); + + // Implementation + const implSelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName))), + ); + const implParamType = t.tsIntersectionType([ + t.tsTypeLiteral([implSelProp]), + omitType( + typeRef('UseMutationOptions', [ + t.tsAnyKeyword(), + typeRef('Error'), + updateVarType, + ]), + ['mutationFn'], + ), + ]); - const mutationOptions: (t.ObjectProperty | t.SpreadElement)[] = []; - if (useCentralizedKeys) { - mutationOptions.push( - t.objectProperty( - t.identifier('mutationKey'), - t.memberExpression(t.identifier(mutationKeysName), t.identifier('all')) - ) - ); - } - mutationOptions.push( - t.objectProperty( - t.identifier('mutationFn'), - t.arrowFunctionExpression( - [typedParam('variables', t.tsTypeReference(t.identifier(`${ucFirst(mutationName)}MutationVariables`)))], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(`${mutationName}MutationDocument`), t.identifier('variables')], - [ - t.tsTypeReference(t.identifier(`${ucFirst(mutationName)}MutationResult`)), - t.tsTypeReference(t.identifier(`${ucFirst(mutationName)}MutationVariables`)), - ] - ) - ) - ) + const body: t.Statement[] = []; + body.push(buildSelectionArgsCall(selectTypeName)); + body.push(destructureParamsWithSelection('mutationOptions')); + body.push(voidStatement('_selection')); + body.push(constDecl('queryClient', callExpr('useQueryClient', []))); + + const mutationKeyExpr = useCentralizedKeys + ? t.memberExpression(t.identifier(mutationKeysName), t.identifier('all')) + : undefined; + + // mutationFn: ({ pkField, patch }: { pkField: type; patch: PatchType }) => + // getClient().singular.update({ where: { pkField }, data: patch, select: ... }).unwrap() + const destructParam = t.objectPattern([ + shorthandProp(pkField.name), + shorthandProp('patch'), + ]); + destructParam.typeAnnotation = t.tsTypeAnnotation(updateVarType); + const mutationFnExpr = t.arrowFunctionExpression( + [destructParam], + getClientCallUnwrap( + singularName, + 'update', + t.objectExpression([ + objectProp('where', t.objectExpression([shorthandProp(pkField.name)])), + objectProp('data', t.identifier('patch')), + objectProp( + 'select', + t.memberExpression(t.identifier('args'), t.identifier('select')), + ), + ]), + ), ); - const detailQueryKey = useCentralizedKeys - ? t.callExpression( + // onSuccess: invalidate detail and lists + const detailKeyExpr = useCentralizedKeys + ? callExpr( t.memberExpression(t.identifier(keysName), t.identifier('detail')), - [t.memberExpression(t.memberExpression(t.identifier('variables'), t.identifier('input')), t.identifier(pkField.name))] + [ + t.memberExpression( + t.identifier('variables'), + t.identifier(pkField.name), + ), + ], ) : t.arrayExpression([ t.stringLiteral(typeName.toLowerCase()), t.stringLiteral('detail'), - t.memberExpression(t.memberExpression(t.identifier('variables'), t.identifier('input')), t.identifier(pkField.name)), + t.memberExpression( + t.identifier('variables'), + t.identifier(pkField.name), + ), + ]); + const listKeyExpr = useCentralizedKeys + ? callExpr( + t.memberExpression(t.identifier(keysName), t.identifier('lists')), + [], + ) + : t.arrayExpression([ + t.stringLiteral(typeName.toLowerCase()), + t.stringLiteral('list'), ]); - const listQueryKey = useCentralizedKeys - ? t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('lists')), []) - : t.arrayExpression([t.stringLiteral(typeName.toLowerCase()), t.stringLiteral('list')]); - - mutationOptions.push( - t.objectProperty( - t.identifier('onSuccess'), - t.arrowFunctionExpression( - [t.identifier('_'), t.identifier('variables')], - t.blockStatement([ - t.expressionStatement( - t.callExpression( - t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), - [t.objectExpression([t.objectProperty(t.identifier('queryKey'), detailQueryKey)])] - ) + const onSuccessParam = t.identifier('_'); + const variablesParam = t.identifier('variables'); + const onSuccessFn = t.arrowFunctionExpression( + [onSuccessParam, variablesParam], + t.blockStatement([ + t.expressionStatement( + callExpr( + t.memberExpression( + t.identifier('queryClient'), + t.identifier('invalidateQueries'), ), - t.expressionStatement( - t.callExpression( - t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), - [t.objectExpression([t.objectProperty(t.identifier('queryKey'), listQueryKey)])] - ) + [t.objectExpression([objectProp('queryKey', detailKeyExpr)])], + ), + ), + t.expressionStatement( + callExpr( + t.memberExpression( + t.identifier('queryClient'), + t.identifier('invalidateQueries'), ), - ]) - ) - ) + [t.objectExpression([objectProp('queryKey', listKeyExpr)])], + ), + ), + ]), ); - mutationOptions.push(t.spreadElement(t.identifier('options'))); - hookBodyStatements.push( - t.returnStatement( - t.callExpression(t.identifier('useMutation'), [t.objectExpression(mutationOptions)]) - ) + body.push( + returnUseMutation( + mutationFnExpr, + [ + objectProp('onSuccess', onSuccessFn), + spreadObj(t.identifier('mutationOptions')), + ], + mutationKeyExpr, + ), ); - const optionsTypeStr = `Omit, 'mutationFn'>`; - const optionsParam = t.identifier('options'); - optionsParam.optional = true; - optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(optionsTypeStr))); - - const hookFunc = t.functionDeclaration( - t.identifier(hookName), - [optionsParam], - t.blockStatement(hookBodyStatements) + statements.push( + exportFunction( + hookName, + null, + [createFunctionParam('params', implParamType)], + body, + ), ); - const hookExport = t.exportNamedDeclaration(hookFunc); - addJSDocComment(hookExport, [ - `Mutation hook for updating a ${typeName}`, - '', - '@example', - '```tsx', - `const { mutate, isPending } = ${hookName}();`, - '', - 'mutate({', - ' input: {', - ` ${pkField.name}: ${pkField.tsType === 'string' ? "'value-here'" : '123'},`, - ' patch: {', - ' // ... fields to update', - ' },', - ' },', - '});', - '```', - ]); - statements.push(hookExport); - - const code = generateCode(statements); - const content = getGeneratedFileHeader(`Update mutation hook for ${typeName}`) + '\n\n' + code; return { fileName: getUpdateMutationFileName(table), - content, + content: generateHookFileCode( + `Update mutation hook for ${typeName}`, + statements, + ), }; } export function generateDeleteMutationHook( table: CleanTable, - options: MutationGeneratorOptions = {} + options: MutationGeneratorOptions = {}, ): GeneratedMutationFile | null { - const { - reactQueryEnabled = true, - useCentralizedKeys = true, - hasRelationships = false, - } = options; - - if (!reactQueryEnabled) { - return null; - } + const { reactQueryEnabled = true, useCentralizedKeys = true } = options; - if (table.query?.delete === null) { - return null; - } + if (!reactQueryEnabled) return null; + if (table.query?.delete === null) return null; + if (!hasValidPrimaryKey(table)) return null; - const { typeName } = getTableNames(table); + const { typeName, singularName } = getTableNames(table); const hookName = getDeleteMutationHookName(table); const mutationName = getDeleteMutationName(table); const keysName = `${lcFirst(typeName)}Keys`; const mutationKeysName = `${lcFirst(typeName)}MutationKeys`; - const scopeTypeName = `${typeName}Scope`; + const selectTypeName = `${typeName}Select`; + const relationTypeName = `${typeName}WithRelations`; const pkFields = getPrimaryKeyInfo(table); const pkField = pkFields[0]; - const mutationAST = buildDeleteMutationAST({ table }); - const mutationDocument = printGraphQL(mutationAST); + const pkTsType = + pkField.tsType === 'string' ? t.tsStringKeyword() : t.tsNumberKeyword(); const statements: t.Statement[] = []; - const reactQueryImport = t.importDeclaration( - [ - t.importSpecifier(t.identifier('useMutation'), t.identifier('useMutation')), - t.importSpecifier(t.identifier('useQueryClient'), t.identifier('useQueryClient')), - ], - t.stringLiteral('@tanstack/react-query') + // Imports + statements.push( + createImportDeclaration('@tanstack/react-query', [ + 'useMutation', + 'useQueryClient', + ]), + ); + statements.push( + createImportDeclaration( + '@tanstack/react-query', + ['UseMutationOptions', 'UseMutationResult'], + true, + ), ); - statements.push(reactQueryImport); - - const reactQueryTypeImport = t.importDeclaration( - [t.importSpecifier(t.identifier('UseMutationOptions'), t.identifier('UseMutationOptions'))], - t.stringLiteral('@tanstack/react-query') + statements.push(createImportDeclaration('../client', ['getClient'])); + statements.push( + createImportDeclaration('../selection', ['buildSelectionArgs']), ); - reactQueryTypeImport.importKind = 'type'; - statements.push(reactQueryTypeImport); - - const clientImport = t.importDeclaration( - [t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], - t.stringLiteral('../client') + statements.push( + createImportDeclaration('../selection', ['SelectionConfig'], true), ); - statements.push(clientImport); if (useCentralizedKeys) { - const queryKeyImport = t.importDeclaration( - [t.importSpecifier(t.identifier(keysName), t.identifier(keysName))], - t.stringLiteral('../query-keys') + statements.push(createImportDeclaration('../query-keys', [keysName])); + statements.push( + createImportDeclaration('../mutation-keys', [mutationKeysName]), ); - statements.push(queryKeyImport); - if (hasRelationships) { - const scopeTypeImport = t.importDeclaration( - [t.importSpecifier(t.identifier(scopeTypeName), t.identifier(scopeTypeName))], - t.stringLiteral('../query-keys') - ); - scopeTypeImport.importKind = 'type'; - statements.push(scopeTypeImport); - } - const mutationKeyImport = t.importDeclaration( - [t.importSpecifier(t.identifier(mutationKeysName), t.identifier(mutationKeysName))], - t.stringLiteral('../mutation-keys') - ); - statements.push(mutationKeyImport); } - const mutationDocConst = t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier(`${mutationName}MutationDocument`), - t.templateLiteral( - [t.templateElement({ raw: '\n' + mutationDocument, cooked: '\n' + mutationDocument }, true)], - [] - ) + statements.push( + createImportDeclaration( + '../../orm/input-types', + [selectTypeName, relationTypeName], + true, ), - ]); - statements.push(t.exportNamedDeclaration(mutationDocConst)); - - const pkTypeAnnotation = - pkField.tsType === 'string' - ? t.tsStringKeyword() - : pkField.tsType === 'number' - ? t.tsNumberKeyword() - : t.tsTypeReference(t.identifier(pkField.tsType)); - - const variablesInterfaceBody = t.tsInterfaceBody([ - t.tsPropertySignature( - t.identifier('input'), - t.tsTypeAnnotation( - t.tsTypeLiteral([ - t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkTypeAnnotation)), - ]) - ) + ); + statements.push( + createImportDeclaration( + '../../orm/select-types', + ['InferSelectResult', 'StrictSelect'], + true, ), - ]); - const variablesInterface = t.tsInterfaceDeclaration( - t.identifier(`${ucFirst(mutationName)}MutationVariables`), - null, - null, - variablesInterfaceBody ); - statements.push(t.exportNamedDeclaration(variablesInterface)); - const clientMutationIdProp = t.tsPropertySignature( - t.identifier('clientMutationId'), - t.tsTypeAnnotation(t.tsUnionType([t.tsStringKeyword(), t.tsNullKeyword()])) + // Re-exports + statements.push( + createTypeReExport( + [selectTypeName, relationTypeName], + '../../orm/input-types', + ), ); - const resultInterfaceBody = t.tsInterfaceBody([ + // Variable type: { pkField: type } + const deleteVarType = t.tsTypeLiteral([ t.tsPropertySignature( - t.identifier(mutationName), - t.tsTypeAnnotation(t.tsTypeLiteral([clientMutationIdProp])) + t.identifier(pkField.name), + t.tsTypeAnnotation(pkTsType), ), ]); - const resultInterface = t.tsInterfaceDeclaration( - t.identifier(`${ucFirst(mutationName)}MutationResult`), - null, - null, - resultInterfaceBody - ); - statements.push(t.exportNamedDeclaration(resultInterface)); - - const hookBodyStatements: t.Statement[] = []; - hookBodyStatements.push( - t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier('queryClient'), - t.callExpression(t.identifier('useQueryClient'), []) + + const resultType = (sel: t.TSType) => + buildMutationResultType(mutationName, singularName, relationTypeName, sel); + + // Overload 1: with fields + const o1ParamType = t.tsIntersectionType([ + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(buildFieldsSelectionType(sRef(), selectTypeName)), ), - ]) - ); + ]), + useMutationOptionsType(resultType(sRef()), deleteVarType), + ]); + const o1 = exportDeclareFunction( + hookName, + createSTypeParam(selectTypeName), + [createFunctionParam('params', o1ParamType)], + useMutationResultType(resultType(sRef()), deleteVarType), + ); + addJSDocComment(o1, [ + `Mutation hook for deleting a ${typeName} with typed selection`, + '', + '@example', + '```tsx', + `const { mutate, isPending } = ${hookName}({`, + ' selection: { fields: { id: true } },', + '});', + '', + `mutate({ ${pkField.name}: ${pkField.tsType === 'string' ? "'value-to-delete'" : '123'} });`, + '```', + ]); + statements.push(o1); + + // Implementation + const implSelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName))), + ); + const implParamType = t.tsIntersectionType([ + t.tsTypeLiteral([implSelProp]), + omitType( + typeRef('UseMutationOptions', [ + t.tsAnyKeyword(), + typeRef('Error'), + deleteVarType, + ]), + ['mutationFn'], + ), + ]); - const mutationOptions: (t.ObjectProperty | t.SpreadElement)[] = []; - if (useCentralizedKeys) { - mutationOptions.push( - t.objectProperty( - t.identifier('mutationKey'), - t.memberExpression(t.identifier(mutationKeysName), t.identifier('all')) - ) - ); - } - mutationOptions.push( - t.objectProperty( - t.identifier('mutationFn'), - t.arrowFunctionExpression( - [typedParam('variables', t.tsTypeReference(t.identifier(`${ucFirst(mutationName)}MutationVariables`)))], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(`${mutationName}MutationDocument`), t.identifier('variables')], - [ - t.tsTypeReference(t.identifier(`${ucFirst(mutationName)}MutationResult`)), - t.tsTypeReference(t.identifier(`${ucFirst(mutationName)}MutationVariables`)), - ] - ) - ) - ) + const body: t.Statement[] = []; + body.push(buildSelectionArgsCall(selectTypeName)); + body.push(destructureParamsWithSelection('mutationOptions')); + body.push(voidStatement('_selection')); + body.push(constDecl('queryClient', callExpr('useQueryClient', []))); + + const mutationKeyExpr = useCentralizedKeys + ? t.memberExpression(t.identifier(mutationKeysName), t.identifier('all')) + : undefined; + + // mutationFn: ({ pkField }: { pkField: type }) => + // getClient().singular.delete({ where: { pkField }, select: ... }).unwrap() + const destructParam = t.objectPattern([shorthandProp(pkField.name)]); + destructParam.typeAnnotation = t.tsTypeAnnotation(deleteVarType); + const mutationFnExpr = t.arrowFunctionExpression( + [destructParam], + getClientCallUnwrap( + singularName, + 'delete', + t.objectExpression([ + objectProp('where', t.objectExpression([shorthandProp(pkField.name)])), + objectProp( + 'select', + t.memberExpression(t.identifier('args'), t.identifier('select')), + ), + ]), + ), ); - const detailQueryKey = useCentralizedKeys - ? t.callExpression( + // onSuccess: remove detail, invalidate lists + const detailKeyExpr = useCentralizedKeys + ? callExpr( t.memberExpression(t.identifier(keysName), t.identifier('detail')), - [t.memberExpression(t.memberExpression(t.identifier('variables'), t.identifier('input')), t.identifier(pkField.name))] + [ + t.memberExpression( + t.identifier('variables'), + t.identifier(pkField.name), + ), + ], ) : t.arrayExpression([ t.stringLiteral(typeName.toLowerCase()), t.stringLiteral('detail'), - t.memberExpression(t.memberExpression(t.identifier('variables'), t.identifier('input')), t.identifier(pkField.name)), + t.memberExpression( + t.identifier('variables'), + t.identifier(pkField.name), + ), + ]); + const listKeyExpr = useCentralizedKeys + ? callExpr( + t.memberExpression(t.identifier(keysName), t.identifier('lists')), + [], + ) + : t.arrayExpression([ + t.stringLiteral(typeName.toLowerCase()), + t.stringLiteral('list'), ]); - const listQueryKey = useCentralizedKeys - ? t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('lists')), []) - : t.arrayExpression([t.stringLiteral(typeName.toLowerCase()), t.stringLiteral('list')]); - - mutationOptions.push( - t.objectProperty( - t.identifier('onSuccess'), - t.arrowFunctionExpression( - [t.identifier('_'), t.identifier('variables')], - t.blockStatement([ - t.expressionStatement( - t.callExpression( - t.memberExpression(t.identifier('queryClient'), t.identifier('removeQueries')), - [t.objectExpression([t.objectProperty(t.identifier('queryKey'), detailQueryKey)])] - ) + const onSuccessFn = t.arrowFunctionExpression( + [t.identifier('_'), t.identifier('variables')], + t.blockStatement([ + t.expressionStatement( + callExpr( + t.memberExpression( + t.identifier('queryClient'), + t.identifier('removeQueries'), ), - t.expressionStatement( - t.callExpression( - t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), - [t.objectExpression([t.objectProperty(t.identifier('queryKey'), listQueryKey)])] - ) + [t.objectExpression([objectProp('queryKey', detailKeyExpr)])], + ), + ), + t.expressionStatement( + callExpr( + t.memberExpression( + t.identifier('queryClient'), + t.identifier('invalidateQueries'), ), - ]) - ) - ) + [t.objectExpression([objectProp('queryKey', listKeyExpr)])], + ), + ), + ]), ); - mutationOptions.push(t.spreadElement(t.identifier('options'))); - hookBodyStatements.push( - t.returnStatement( - t.callExpression(t.identifier('useMutation'), [t.objectExpression(mutationOptions)]) - ) + body.push( + returnUseMutation( + mutationFnExpr, + [ + objectProp('onSuccess', onSuccessFn), + spreadObj(t.identifier('mutationOptions')), + ], + mutationKeyExpr, + ), ); - const optionsTypeStr = `Omit, 'mutationFn'>`; - const optionsParam = t.identifier('options'); - optionsParam.optional = true; - optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(optionsTypeStr))); - - const hookFunc = t.functionDeclaration( - t.identifier(hookName), - [optionsParam], - t.blockStatement(hookBodyStatements) + statements.push( + exportFunction( + hookName, + null, + [createFunctionParam('params', implParamType)], + body, + ), ); - const hookExport = t.exportNamedDeclaration(hookFunc); - addJSDocComment(hookExport, [ - `Mutation hook for deleting a ${typeName}`, - '', - '@example', - '```tsx', - `const { mutate, isPending } = ${hookName}();`, - '', - 'mutate({', - ' input: {', - ` ${pkField.name}: ${pkField.tsType === 'string' ? "'value-to-delete'" : '123'},`, - ' },', - '});', - '```', - ]); - statements.push(hookExport); - - const code = generateCode(statements); - const content = getGeneratedFileHeader(`Delete mutation hook for ${typeName}`) + '\n\n' + code; return { fileName: getDeleteMutationFileName(table), - content, + content: generateHookFileCode( + `Delete mutation hook for ${typeName}`, + statements, + ), }; } export function generateAllMutationHooks( tables: CleanTable[], - options: MutationGeneratorOptions = {} + options: MutationGeneratorOptions = {}, ): GeneratedMutationFile[] { const files: GeneratedMutationFile[] = []; diff --git a/graphql/codegen/src/core/codegen/orm/barrel.ts b/graphql/codegen/src/core/codegen/orm/barrel.ts index fda3b5b15..bc90b0445 100644 --- a/graphql/codegen/src/core/codegen/orm/barrel.ts +++ b/graphql/codegen/src/core/codegen/orm/barrel.ts @@ -3,10 +3,11 @@ * * Generates index.ts files that re-export all models and operations. */ -import type { CleanTable } from '../../../types/schema'; import * as t from '@babel/types'; + +import type { CleanTable } from '../../../types/schema'; import { generateCode } from '../babel-ast'; -import { getTableNames, lcFirst, getGeneratedFileHeader } from '../utils'; +import { getGeneratedFileHeader, getTableNames, lcFirst } from '../utils'; export interface GeneratedBarrelFile { fileName: string; @@ -16,7 +17,9 @@ export interface GeneratedBarrelFile { /** * Generate the models/index.ts barrel file */ -export function generateModelsBarrel(tables: CleanTable[]): GeneratedBarrelFile { +export function generateModelsBarrel( + tables: CleanTable[], +): GeneratedBarrelFile { const statements: t.Statement[] = []; // Export all model classes (Select types are now in input-types.ts) @@ -25,13 +28,14 @@ export function generateModelsBarrel(tables: CleanTable[]): GeneratedBarrelFile const modelName = `${typeName}Model`; // Use same naming logic as model-generator to avoid "index.ts" clash with barrel file const baseFileName = lcFirst(typeName); - const moduleFileName = baseFileName === 'index' ? `${baseFileName}Model` : baseFileName; + const moduleFileName = + baseFileName === 'index' ? `${baseFileName}Model` : baseFileName; // Create: export { ModelName } from './moduleName'; const exportDecl = t.exportNamedDeclaration( null, [t.exportSpecifier(t.identifier(modelName), t.identifier(modelName))], - t.stringLiteral(`./${moduleFileName}`) + t.stringLiteral(`./${moduleFileName}`), ); statements.push(exportDecl); } @@ -48,7 +52,9 @@ export function generateModelsBarrel(tables: CleanTable[]): GeneratedBarrelFile /** * Generate the types.ts file that re-exports all types */ -export function generateTypesBarrel(_useSharedTypes: boolean): GeneratedBarrelFile { +export function generateTypesBarrel( + _useSharedTypes: boolean, +): GeneratedBarrelFile { // Always re-export from input-types since that's where all types are generated const content = `/** * Types re-export diff --git a/graphql/codegen/src/core/codegen/orm/client-generator.ts b/graphql/codegen/src/core/codegen/orm/client-generator.ts index 765d95807..822399f7e 100644 --- a/graphql/codegen/src/core/codegen/orm/client-generator.ts +++ b/graphql/codegen/src/core/codegen/orm/client-generator.ts @@ -3,13 +3,14 @@ * * Generates the createClient() factory function and main client file. */ -import type { CleanTable } from '../../../types/schema'; import * as t from '@babel/types'; -import { generateCode, commentBlock } from '../babel-ast'; -import { getTableNames, lcFirst, getGeneratedFileHeader } from '../utils'; import * as fs from 'fs'; import * as path from 'path'; +import type { CleanTable } from '../../../types/schema'; +import { commentBlock, generateCode } from '../babel-ast'; +import { getGeneratedFileHeader, getTableNames, lcFirst } from '../utils'; + export interface GeneratedClientFile { fileName: string; content: string; @@ -28,7 +29,7 @@ function findTemplateFile(templateName: string): string { throw new Error( `Could not find template file: ${templateName}. ` + - `Searched in: ${templatePath}` + `Searched in: ${templatePath}`, ); } @@ -46,7 +47,7 @@ function readTemplateFile(templateName: string, description: string): string { content = content.replace( headerPattern, - getGeneratedFileHeader(description) + '\n' + getGeneratedFileHeader(description) + '\n', ); return content; @@ -61,7 +62,10 @@ function readTemplateFile(templateName: string, description: string): string { export function generateOrmClientFile(): GeneratedClientFile { return { fileName: 'client.ts', - content: readTemplateFile('orm-client.ts', 'ORM Client - Runtime GraphQL executor'), + content: readTemplateFile( + 'orm-client.ts', + 'ORM Client - Runtime GraphQL executor', + ), }; } @@ -75,7 +79,7 @@ export function generateQueryBuilderFile(): GeneratedClientFile { fileName: 'query-builder.ts', content: readTemplateFile( 'query-builder.ts', - 'Query Builder - Builds and executes GraphQL operations' + 'Query Builder - Builds and executes GraphQL operations', ), }; } @@ -88,21 +92,24 @@ export function generateQueryBuilderFile(): GeneratedClientFile { export function generateSelectTypesFile(): GeneratedClientFile { return { fileName: 'select-types.ts', - content: readTemplateFile('select-types.ts', 'Type utilities for select inference'), + content: readTemplateFile( + 'select-types.ts', + 'Type utilities for select inference', + ), }; } function createImportDeclaration( moduleSpecifier: string, namedImports: string[], - typeOnly: boolean = false + typeOnly: boolean = false, ): t.ImportDeclaration { const specifiers = namedImports.map((name) => - t.importSpecifier(t.identifier(name), t.identifier(name)) + t.importSpecifier(t.identifier(name), t.identifier(name)), ); const decl = t.importDeclaration( specifiers, - t.stringLiteral(moduleSpecifier) + t.stringLiteral(moduleSpecifier), ); decl.importKind = typeOnly ? 'type' : 'value'; return decl; @@ -114,7 +121,7 @@ function createImportDeclaration( export function generateCreateClientFile( tables: CleanTable[], hasCustomQueries: boolean, - hasCustomMutations: boolean + hasCustomMutations: boolean, ): GeneratedClientFile { const statements: t.Statement[] = []; @@ -122,7 +129,7 @@ export function generateCreateClientFile( // Import OrmClient (value) and OrmClientConfig (type) separately statements.push(createImportDeclaration('./client', ['OrmClient'])); statements.push( - createImportDeclaration('./client', ['OrmClientConfig'], true) + createImportDeclaration('./client', ['OrmClientConfig'], true), ); // Import models @@ -131,19 +138,19 @@ export function generateCreateClientFile( const modelName = `${typeName}Model`; const fileName = lcFirst(typeName); statements.push( - createImportDeclaration(`./models/${fileName}`, [modelName]) + createImportDeclaration(`./models/${fileName}`, [modelName]), ); } // Import custom operations if (hasCustomQueries) { statements.push( - createImportDeclaration('./query', ['createQueryOperations']) + createImportDeclaration('./query', ['createQueryOperations']), ); } if (hasCustomMutations) { statements.push( - createImportDeclaration('./mutation', ['createMutationOperations']) + createImportDeclaration('./mutation', ['createMutationOperations']), ); } @@ -154,22 +161,22 @@ export function generateCreateClientFile( [ t.exportSpecifier( t.identifier('OrmClientConfig'), - t.identifier('OrmClientConfig') + t.identifier('OrmClientConfig'), ), t.exportSpecifier( t.identifier('QueryResult'), - t.identifier('QueryResult') + t.identifier('QueryResult'), ), t.exportSpecifier( t.identifier('GraphQLError'), - t.identifier('GraphQLError') + t.identifier('GraphQLError'), ), t.exportSpecifier( t.identifier('GraphQLAdapter'), - t.identifier('GraphQLAdapter') + t.identifier('GraphQLAdapter'), ), ], - t.stringLiteral('./client') + t.stringLiteral('./client'), ); typeExportDecl.exportKind = 'type'; statements.push(typeExportDecl); @@ -181,11 +188,11 @@ export function generateCreateClientFile( [ t.exportSpecifier( t.identifier('GraphQLRequestError'), - t.identifier('GraphQLRequestError') + t.identifier('GraphQLRequestError'), ), ], - t.stringLiteral('./client') - ) + t.stringLiteral('./client'), + ), ); // export { QueryBuilder } from './query-builder'; @@ -195,11 +202,11 @@ export function generateCreateClientFile( [ t.exportSpecifier( t.identifier('QueryBuilder'), - t.identifier('QueryBuilder') + t.identifier('QueryBuilder'), ), ], - t.stringLiteral('./query-builder') - ) + t.stringLiteral('./query-builder'), + ), ); // export * from './select-types'; @@ -216,11 +223,11 @@ export function generateCreateClientFile( [ t.exportSpecifier( t.identifier('createQueryOperations'), - t.identifier('createQueryOperations') + t.identifier('createQueryOperations'), ), ], - t.stringLiteral('./query') - ) + t.stringLiteral('./query'), + ), ); } if (hasCustomMutations) { @@ -230,11 +237,11 @@ export function generateCreateClientFile( [ t.exportSpecifier( t.identifier('createMutationOperations'), - t.identifier('createMutationOperations') + t.identifier('createMutationOperations'), ), ], - t.stringLiteral('./mutation') - ) + t.stringLiteral('./mutation'), + ), ); } @@ -247,8 +254,8 @@ export function generateCreateClientFile( returnProperties.push( t.objectProperty( t.identifier(singularName), - t.newExpression(t.identifier(modelName), [t.identifier('client')]) - ) + t.newExpression(t.identifier(modelName), [t.identifier('client')]), + ), ); } @@ -258,8 +265,8 @@ export function generateCreateClientFile( t.identifier('query'), t.callExpression(t.identifier('createQueryOperations'), [ t.identifier('client'), - ]) - ) + ]), + ), ); } @@ -269,8 +276,8 @@ export function generateCreateClientFile( t.identifier('mutation'), t.callExpression(t.identifier('createMutationOperations'), [ t.identifier('client'), - ]) - ) + ]), + ), ); } @@ -278,7 +285,7 @@ export function generateCreateClientFile( const clientDecl = t.variableDeclaration('const', [ t.variableDeclarator( t.identifier('client'), - t.newExpression(t.identifier('OrmClient'), [t.identifier('config')]) + t.newExpression(t.identifier('OrmClient'), [t.identifier('config')]), ), ]); @@ -286,13 +293,13 @@ export function generateCreateClientFile( const configParam = t.identifier('config'); configParam.typeAnnotation = t.tsTypeAnnotation( - t.tsTypeReference(t.identifier('OrmClientConfig')) + t.tsTypeReference(t.identifier('OrmClientConfig')), ); const createClientFunc = t.functionDeclaration( t.identifier('createClient'), [configParam], - t.blockStatement([clientDecl, returnStmt]) + t.blockStatement([clientDecl, returnStmt]), ); // Add JSDoc comment diff --git a/graphql/codegen/src/core/codegen/orm/client.ts b/graphql/codegen/src/core/codegen/orm/client.ts index f7e233531..194f5f9de 100644 --- a/graphql/codegen/src/core/codegen/orm/client.ts +++ b/graphql/codegen/src/core/codegen/orm/client.ts @@ -26,7 +26,7 @@ export type QueryResult = export interface GraphQLAdapter { execute( document: string, - variables?: Record + variables?: Record, ): Promise>; setHeaders?(headers: Record): void; getEndpoint?(): string; @@ -40,14 +40,14 @@ export class FetchAdapter implements GraphQLAdapter { constructor( private endpoint: string, - headers?: Record + headers?: Record, ) { this.headers = headers ?? {}; } async execute( document: string, - variables?: Record + variables?: Record, ): Promise> { const response = await fetch(this.endpoint, { method: 'POST', @@ -66,7 +66,9 @@ export class FetchAdapter implements GraphQLAdapter { return { ok: false, data: null, - errors: [{ message: `HTTP ${response.status}: ${response.statusText}` }], + errors: [ + { message: `HTTP ${response.status}: ${response.statusText}` }, + ], }; } @@ -114,7 +116,7 @@ export interface OrmClientConfig { export class GraphQLRequestError extends Error { constructor( public readonly errors: GraphQLError[], - public readonly data: unknown = null + public readonly data: unknown = null, ) { const messages = errors.map((e) => e.message).join('; '); super(`GraphQL Error: ${messages}`); @@ -132,14 +134,14 @@ export class OrmClient { this.adapter = new FetchAdapter(config.endpoint, config.headers); } else { throw new Error( - 'OrmClientConfig requires either an endpoint or a custom adapter' + 'OrmClientConfig requires either an endpoint or a custom adapter', ); } } async execute( document: string, - variables?: Record + variables?: Record, ): Promise> { return this.adapter.execute(document, variables); } diff --git a/graphql/codegen/src/core/codegen/orm/custom-ops-generator.ts b/graphql/codegen/src/core/codegen/orm/custom-ops-generator.ts index 0e7a55cb0..c170e9738 100644 --- a/graphql/codegen/src/core/codegen/orm/custom-ops-generator.ts +++ b/graphql/codegen/src/core/codegen/orm/custom-ops-generator.ts @@ -4,16 +4,17 @@ * Generates db.query.* and db.mutation.* namespaces for non-table operations * like login, register, currentUser, etc. */ -import type { CleanOperation, CleanArgument } from '../../../types/schema'; import * as t from '@babel/types'; + +import type { CleanArgument, CleanOperation } from '../../../types/schema'; import { generateCode } from '../babel-ast'; -import { ucFirst, getGeneratedFileHeader } from '../utils'; +import { NON_SELECT_TYPES, getSelectTypeName } from '../select-helpers'; import { - typeRefToTsType, - isTypeRequired, getTypeBaseName, + isTypeRequired, + typeRefToTsType, } from '../type-resolver'; -import { SCALAR_NAMES } from '../scalars'; +import { getGeneratedFileHeader, ucFirst } from '../utils'; export interface GeneratedCustomOpsFile { fileName: string; @@ -45,19 +46,12 @@ function collectInputTypeNamesFromOps(operations: CleanOperation[]): string[] { return Array.from(inputTypes); } -// Types that don't need Select types -const NON_SELECT_TYPES = new Set([ - ...SCALAR_NAMES, - 'Query', - 'Mutation', -]); - /** * Collect all payload/return type names from operations (for Select types) * Filters out scalar types */ function collectPayloadTypeNamesFromOps( - operations: CleanOperation[] + operations: CleanOperation[], ): string[] { const payloadTypes = new Set(); @@ -66,8 +60,6 @@ function collectPayloadTypeNamesFromOps( if ( baseName && !baseName.endsWith('Connection') && - baseName !== 'Query' && - baseName !== 'Mutation' && !NON_SELECT_TYPES.has(baseName) ) { payloadTypes.add(baseName); @@ -78,38 +70,44 @@ function collectPayloadTypeNamesFromOps( } /** - * Get the Select type name for a return type - * Returns null for scalar types, Connection types (no select needed) + * Collect Connection and other non-scalar return type names that need importing + * (for typing QueryBuilder results on scalar/Connection operations) */ -function getSelectTypeName(returnType: CleanArgument['type']): string | null { - const baseName = getTypeBaseName(returnType); - if ( - baseName && - !NON_SELECT_TYPES.has(baseName) && - baseName !== 'Query' && - baseName !== 'Mutation' && - !baseName.endsWith('Connection') - ) { - return `${baseName}Select`; +function collectRawReturnTypeNames(operations: CleanOperation[]): string[] { + const types = new Set(); + + for (const op of operations) { + const baseName = getTypeBaseName(op.returnType); + if ( + baseName && + !NON_SELECT_TYPES.has(baseName) && + baseName.endsWith('Connection') + ) { + types.add(baseName); + } } - return null; + + return Array.from(types); } function createImportDeclaration( moduleSpecifier: string, namedImports: string[], - typeOnly: boolean = false + typeOnly: boolean = false, ): t.ImportDeclaration { const specifiers = namedImports.map((name) => - t.importSpecifier(t.identifier(name), t.identifier(name)) + t.importSpecifier(t.identifier(name), t.identifier(name)), + ); + const decl = t.importDeclaration( + specifiers, + t.stringLiteral(moduleSpecifier), ); - const decl = t.importDeclaration(specifiers, t.stringLiteral(moduleSpecifier)); decl.importKind = typeOnly ? 'type' : 'value'; return decl; } function createVariablesInterface( - op: CleanOperation + op: CleanOperation, ): t.ExportNamedDeclaration | null { if (op.args.length === 0) return null; @@ -118,7 +116,7 @@ function createVariablesInterface( const optional = !isTypeRequired(arg.type); const prop = t.tsPropertySignature( t.identifier(arg.name), - t.tsTypeAnnotation(parseTypeAnnotation(typeRefToTsType(arg.type))) + t.tsTypeAnnotation(parseTypeAnnotation(typeRefToTsType(arg.type))), ); prop.optional = optional; return prop; @@ -128,7 +126,7 @@ function createVariablesInterface( t.identifier(varTypeName), null, null, - t.tsInterfaceBody(props) + t.tsInterfaceBody(props), ); return t.exportNamedDeclaration(interfaceDecl); } @@ -142,7 +140,9 @@ function parseTypeAnnotation(typeStr: string): t.TSType { if (typeStr === 'unknown') return t.tsUnknownKeyword(); if (typeStr.includes(' | ')) { - const parts = typeStr.split(' | ').map((p) => parseTypeAnnotation(p.trim())); + const parts = typeStr + .split(' | ') + .map((p) => parseTypeAnnotation(p.trim())); return t.tsUnionType(parts); } @@ -153,9 +153,38 @@ function parseTypeAnnotation(typeStr: string): t.TSType { return t.tsTypeReference(t.identifier(typeStr)); } +function buildSelectedResultTsType( + typeRef: CleanArgument['type'], + payloadTypeName: string, +): t.TSType { + if (typeRef.kind === 'NON_NULL' && typeRef.ofType) { + return buildSelectedResultTsType( + typeRef.ofType as CleanArgument['type'], + payloadTypeName, + ); + } + + if (typeRef.kind === 'LIST' && typeRef.ofType) { + return t.tsArrayType( + buildSelectedResultTsType( + typeRef.ofType as CleanArgument['type'], + payloadTypeName, + ), + ); + } + + return t.tsTypeReference( + t.identifier('InferSelectResult'), + t.tsTypeParameterInstantiation([ + t.tsTypeReference(t.identifier(payloadTypeName)), + t.tsTypeReference(t.identifier('S')), + ]), + ); +} + function buildOperationMethod( op: CleanOperation, - operationType: 'query' | 'mutation' + operationType: 'query' | 'mutation', ): t.ObjectProperty { const hasArgs = op.args.length > 0; const varTypeName = `${ucFirst(op.name)}Variables`; @@ -172,34 +201,31 @@ function buildOperationMethod( if (hasArgs) { const argsParam = t.identifier('args'); - argsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(varTypeName))); + argsParam.typeAnnotation = t.tsTypeAnnotation( + t.tsTypeReference(t.identifier(varTypeName)), + ); params.push(argsParam); } const optionsParam = t.identifier('options'); - optionsParam.optional = true; + optionsParam.optional = !selectTypeName; if (selectTypeName) { - // Use DeepExact to enforce strict field validation - // This catches invalid fields even when mixed with valid ones + const selectProp = t.tsPropertySignature( + t.identifier('select'), + t.tsTypeAnnotation(t.tsTypeReference(t.identifier('S'))), + ); + selectProp.optional = false; optionsParam.typeAnnotation = t.tsTypeAnnotation( - t.tsTypeLiteral([ - (() => { - const prop = t.tsPropertySignature( - t.identifier('select'), - t.tsTypeAnnotation( - t.tsTypeReference( - t.identifier('DeepExact'), - t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier('S')), - t.tsTypeReference(t.identifier(selectTypeName)), - ]) - ) - ) - ); - prop.optional = true; - return prop; - })(), - ]) + t.tsIntersectionType([ + t.tsTypeLiteral([selectProp]), + t.tsTypeReference( + t.identifier('StrictSelect'), + t.tsTypeParameterInstantiation([ + t.tsTypeReference(t.identifier('S')), + t.tsTypeReference(t.identifier(selectTypeName)), + ]), + ), + ]), ); } else { optionsParam.typeAnnotation = t.tsTypeAnnotation( @@ -210,60 +236,94 @@ function buildOperationMethod( t.tsTypeAnnotation( t.tsTypeReference( t.identifier('Record'), - t.tsTypeParameterInstantiation([t.tsStringKeyword(), t.tsUnknownKeyword()]) - ) - ) + t.tsTypeParameterInstantiation([ + t.tsStringKeyword(), + t.tsUnknownKeyword(), + ]), + ), + ), ); prop.optional = true; return prop; })(), - ]) + ]), ); } params.push(optionsParam); // Build the QueryBuilder call + const selectExpr = selectTypeName + ? t.memberExpression(t.identifier('options'), t.identifier('select')) + : t.optionalMemberExpression( + t.identifier('options'), + t.identifier('select'), + false, + true, + ); + const entityTypeExpr = + selectTypeName && payloadTypeName + ? t.stringLiteral(payloadTypeName) + : t.identifier('undefined'); + const queryBuilderArgs = t.objectExpression([ - t.objectProperty(t.identifier('client'), t.identifier('client'), false, true), + t.objectProperty( + t.identifier('client'), + t.identifier('client'), + false, + true, + ), t.objectProperty(t.identifier('operation'), t.stringLiteral(operationType)), - t.objectProperty(t.identifier('operationName'), t.stringLiteral(ucFirst(op.name))), + t.objectProperty( + t.identifier('operationName'), + t.stringLiteral(ucFirst(op.name)), + ), t.objectProperty(t.identifier('fieldName'), t.stringLiteral(op.name)), t.spreadElement( t.callExpression(t.identifier('buildCustomDocument'), [ t.stringLiteral(operationType), t.stringLiteral(ucFirst(op.name)), t.stringLiteral(op.name), - t.optionalMemberExpression(t.identifier('options'), t.identifier('select'), false, true), + selectExpr, hasArgs ? t.identifier('args') : t.identifier('undefined'), t.arrayExpression( varDefs.map((v) => t.objectExpression([ t.objectProperty(t.identifier('name'), t.stringLiteral(v.name)), t.objectProperty(t.identifier('type'), t.stringLiteral(v.type)), - ]) - ) + ]), + ), ), - ]) + t.identifier('connectionFieldsMap'), + entityTypeExpr, + ]), ), ]); - const newExpr = t.newExpression(t.identifier('QueryBuilder'), [queryBuilderArgs]); + const newExpr = t.newExpression(t.identifier('QueryBuilder'), [ + queryBuilderArgs, + ]); - // Add type parameter if we have a select type + // Add type parameter to QueryBuilder for typed .unwrap() results if (selectTypeName && payloadTypeName) { + // Select-based type: use InferSelectResult (newExpr as any).typeParameters = t.tsTypeParameterInstantiation([ t.tsTypeLiteral([ t.tsPropertySignature( t.identifier(op.name), t.tsTypeAnnotation( - t.tsTypeReference( - t.identifier('InferSelectResult'), - t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier(payloadTypeName)), - t.tsTypeReference(t.identifier('S')), - ]) - ) - ) + buildSelectedResultTsType(op.returnType, payloadTypeName), + ), + ), + ]), + ]); + } else { + // Scalar/Connection type: use raw TS type directly + const rawTsType = typeRefToTsType(op.returnType); + (newExpr as any).typeParameters = t.tsTypeParameterInstantiation([ + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier(op.name), + t.tsTypeAnnotation(parseTypeAnnotation(rawTsType)), ), ]), ]); @@ -276,9 +336,8 @@ function buildOperationMethod( const typeParam = t.tsTypeParameter( t.tsTypeReference(t.identifier(selectTypeName)), null, - 'S' + 'S', ); - (typeParam as any).const = true; arrowFunc.typeParameters = t.tsTypeParameterDeclaration([typeParam]); } @@ -289,7 +348,7 @@ function buildOperationMethod( * Generate the query/index.ts file for custom query operations */ export function generateCustomQueryOpsFile( - operations: CleanOperation[] + operations: CleanOperation[], ): GeneratedCustomOpsFile { const statements: t.Statement[] = []; @@ -297,16 +356,40 @@ export function generateCustomQueryOpsFile( const inputTypeNames = collectInputTypeNamesFromOps(operations); const payloadTypeNames = collectPayloadTypeNamesFromOps(operations); const selectTypeNames = payloadTypeNames.map((p) => `${p}Select`); - const allTypeImports = [...new Set([...inputTypeNames, ...payloadTypeNames, ...selectTypeNames])]; + const rawReturnTypeNames = collectRawReturnTypeNames(operations); + const allTypeImports = [ + ...new Set([ + ...inputTypeNames, + ...payloadTypeNames, + ...selectTypeNames, + ...rawReturnTypeNames, + ]), + ]; // Add imports statements.push(createImportDeclaration('../client', ['OrmClient'])); - statements.push(createImportDeclaration('../query-builder', ['QueryBuilder', 'buildCustomDocument'])); - statements.push(createImportDeclaration('../select-types', ['InferSelectResult', 'DeepExact'], true)); + statements.push( + createImportDeclaration('../query-builder', [ + 'QueryBuilder', + 'buildCustomDocument', + ]), + ); + statements.push( + createImportDeclaration( + '../select-types', + ['InferSelectResult', 'StrictSelect'], + true, + ), + ); if (allTypeImports.length > 0) { - statements.push(createImportDeclaration('../input-types', allTypeImports, true)); + statements.push( + createImportDeclaration('../input-types', allTypeImports, true), + ); } + statements.push( + createImportDeclaration('../input-types', ['connectionFieldsMap']), + ); // Generate variable interfaces for (const op of operations) { @@ -315,18 +398,22 @@ export function generateCustomQueryOpsFile( } // Generate factory function - const operationProperties = operations.map((op) => buildOperationMethod(op, 'query')); + const operationProperties = operations.map((op) => + buildOperationMethod(op, 'query'), + ); const returnObj = t.objectExpression(operationProperties); const returnStmt = t.returnStatement(returnObj); const clientParam = t.identifier('client'); - clientParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('OrmClient'))); + clientParam.typeAnnotation = t.tsTypeAnnotation( + t.tsTypeReference(t.identifier('OrmClient')), + ); const factoryFunc = t.functionDeclaration( t.identifier('createQueryOperations'), [clientParam], - t.blockStatement([returnStmt]) + t.blockStatement([returnStmt]), ); statements.push(t.exportNamedDeclaration(factoryFunc)); @@ -343,7 +430,7 @@ export function generateCustomQueryOpsFile( * Generate the mutation/index.ts file for custom mutation operations */ export function generateCustomMutationOpsFile( - operations: CleanOperation[] + operations: CleanOperation[], ): GeneratedCustomOpsFile { const statements: t.Statement[] = []; @@ -351,16 +438,40 @@ export function generateCustomMutationOpsFile( const inputTypeNames = collectInputTypeNamesFromOps(operations); const payloadTypeNames = collectPayloadTypeNamesFromOps(operations); const selectTypeNames = payloadTypeNames.map((p) => `${p}Select`); - const allTypeImports = [...new Set([...inputTypeNames, ...payloadTypeNames, ...selectTypeNames])]; + const rawReturnTypeNames = collectRawReturnTypeNames(operations); + const allTypeImports = [ + ...new Set([ + ...inputTypeNames, + ...payloadTypeNames, + ...selectTypeNames, + ...rawReturnTypeNames, + ]), + ]; // Add imports statements.push(createImportDeclaration('../client', ['OrmClient'])); - statements.push(createImportDeclaration('../query-builder', ['QueryBuilder', 'buildCustomDocument'])); - statements.push(createImportDeclaration('../select-types', ['InferSelectResult', 'DeepExact'], true)); + statements.push( + createImportDeclaration('../query-builder', [ + 'QueryBuilder', + 'buildCustomDocument', + ]), + ); + statements.push( + createImportDeclaration( + '../select-types', + ['InferSelectResult', 'StrictSelect'], + true, + ), + ); if (allTypeImports.length > 0) { - statements.push(createImportDeclaration('../input-types', allTypeImports, true)); + statements.push( + createImportDeclaration('../input-types', allTypeImports, true), + ); } + statements.push( + createImportDeclaration('../input-types', ['connectionFieldsMap']), + ); // Generate variable interfaces for (const op of operations) { @@ -369,18 +480,22 @@ export function generateCustomMutationOpsFile( } // Generate factory function - const operationProperties = operations.map((op) => buildOperationMethod(op, 'mutation')); + const operationProperties = operations.map((op) => + buildOperationMethod(op, 'mutation'), + ); const returnObj = t.objectExpression(operationProperties); const returnStmt = t.returnStatement(returnObj); const clientParam = t.identifier('client'); - clientParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('OrmClient'))); + clientParam.typeAnnotation = t.tsTypeAnnotation( + t.tsTypeReference(t.identifier('OrmClient')), + ); const factoryFunc = t.functionDeclaration( t.identifier('createMutationOperations'), [clientParam], - t.blockStatement([returnStmt]) + t.blockStatement([returnStmt]), ); statements.push(t.exportNamedDeclaration(factoryFunc)); diff --git a/graphql/codegen/src/core/codegen/orm/index.ts b/graphql/codegen/src/core/codegen/orm/index.ts index 099826959..489607f56 100644 --- a/graphql/codegen/src/core/codegen/orm/index.ts +++ b/graphql/codegen/src/core/codegen/orm/index.ts @@ -4,21 +4,29 @@ * Main entry point for ORM code generation. Coordinates all generators * and produces the complete ORM client output. */ -import type { CleanTable, CleanOperation, TypeRegistry } from '../../../types/schema'; import type { GraphQLSDKConfigTarget } from '../../../types/config'; +import type { + CleanOperation, + CleanTable, + TypeRegistry, +} from '../../../types/schema'; +import { generateModelsBarrel, generateTypesBarrel } from './barrel'; import { + generateCreateClientFile, generateOrmClientFile, generateQueryBuilderFile, generateSelectTypesFile, - generateCreateClientFile, } from './client-generator'; -import { generateAllModelFiles } from './model-generator'; import { - generateCustomQueryOpsFile, generateCustomMutationOpsFile, + generateCustomQueryOpsFile, } from './custom-ops-generator'; -import { generateModelsBarrel, generateTypesBarrel } from './barrel'; -import { generateInputTypesFile, collectInputTypeNames, collectPayloadTypeNames } from './input-types-generator'; +import { + collectInputTypeNames, + collectPayloadTypeNames, + generateInputTypesFile, +} from './input-types-generator'; +import { generateAllModelFiles } from './model-generator'; export interface GeneratedFile { path: string; @@ -70,10 +78,16 @@ export function generateOrm(options: GenerateOrmOptions): GenerateOrmResult { files.push({ path: clientFile.fileName, content: clientFile.content }); const queryBuilderFile = generateQueryBuilderFile(); - files.push({ path: queryBuilderFile.fileName, content: queryBuilderFile.content }); + files.push({ + path: queryBuilderFile.fileName, + content: queryBuilderFile.content, + }); const selectTypesFile = generateSelectTypesFile(); - files.push({ path: selectTypesFile.fileName, content: selectTypesFile.content }); + files.push({ + path: selectTypesFile.fileName, + content: selectTypesFile.content, + }); // 2. Generate model files const modelFiles = generateAllModelFiles(tables, useSharedTypes); @@ -90,7 +104,10 @@ export function generateOrm(options: GenerateOrmOptions): GenerateOrmResult { // 4. Generate comprehensive input types (entities, filters, orderBy, CRUD inputs, custom inputs, payload types) // Always generate if we have tables or custom operations - if (tables.length > 0 || (typeRegistry && (hasCustomQueries || hasCustomMutations))) { + if ( + tables.length > 0 || + (typeRegistry && (hasCustomQueries || hasCustomMutations)) + ) { const allOps = [ ...(customOperations?.queries ?? []), ...(customOperations?.mutations ?? []), @@ -120,9 +137,12 @@ export function generateOrm(options: GenerateOrmOptions): GenerateOrmResult { typeRegistry ?? new Map(), usedInputTypes, tables, - usedPayloadTypes + usedPayloadTypes, ); - files.push({ path: inputTypesFile.fileName, content: inputTypesFile.content }); + files.push({ + path: inputTypesFile.fileName, + content: inputTypesFile.content, + }); } // 5. Generate custom operations (if any) @@ -132,8 +152,13 @@ export function generateOrm(options: GenerateOrmOptions): GenerateOrmResult { } if (hasCustomMutations && customOperations?.mutations) { - const mutationOpsFile = generateCustomMutationOpsFile(customOperations.mutations); - files.push({ path: mutationOpsFile.fileName, content: mutationOpsFile.content }); + const mutationOpsFile = generateCustomMutationOpsFile( + customOperations.mutations, + ); + files.push({ + path: mutationOpsFile.fileName, + content: mutationOpsFile.content, + }); } // 6. Generate types barrel @@ -141,7 +166,11 @@ export function generateOrm(options: GenerateOrmOptions): GenerateOrmResult { files.push({ path: typesBarrel.fileName, content: typesBarrel.content }); // 7. Generate main index.ts with createClient - const indexFile = generateCreateClientFile(tables, hasCustomQueries, hasCustomMutations); + const indexFile = generateCreateClientFile( + tables, + hasCustomQueries, + hasCustomMutations, + ); files.push({ path: indexFile.fileName, content: indexFile.content }); return { @@ -156,11 +185,14 @@ export function generateOrm(options: GenerateOrmOptions): GenerateOrmResult { } // Re-export generators for direct use +export { generateModelsBarrel, generateTypesBarrel } from './barrel'; export { generateOrmClientFile, generateQueryBuilderFile, generateSelectTypesFile, } from './client-generator'; -export { generateModelFile, generateAllModelFiles } from './model-generator'; -export { generateCustomQueryOpsFile, generateCustomMutationOpsFile } from './custom-ops-generator'; -export { generateModelsBarrel, generateTypesBarrel } from './barrel'; +export { + generateCustomMutationOpsFile, + generateCustomQueryOpsFile, +} from './custom-ops-generator'; +export { generateAllModelFiles, generateModelFile } from './model-generator'; diff --git a/graphql/codegen/src/core/codegen/orm/input-types-generator.ts b/graphql/codegen/src/core/codegen/orm/input-types-generator.ts index ca7154c57..3334a5b11 100644 --- a/graphql/codegen/src/core/codegen/orm/input-types-generator.ts +++ b/graphql/codegen/src/core/codegen/orm/input-types-generator.ts @@ -10,24 +10,26 @@ * * Uses Babel AST for robust code generation. */ +import * as t from '@babel/types'; +import { pluralize } from 'inflekt'; + import type { - TypeRegistry, CleanArgument, CleanTable, + TypeRegistry, } from '../../../types/schema'; -import * as t from '@babel/types'; -import { generateCode, addLineComment } from '../babel-ast'; +import { addLineComment, generateCode } from '../babel-ast'; +import { scalarToFilterType, scalarToTsType } from '../scalars'; +import { getTypeBaseName } from '../type-resolver'; import { - getTableNames, - getFilterTypeName, getConditionTypeName, + getFilterTypeName, + getGeneratedFileHeader, getOrderByTypeName, + getPrimaryKeyInfo, + getTableNames, isRelationField, - getGeneratedFileHeader, } from '../utils'; -import { pluralize } from 'inflekt'; -import { getTypeBaseName } from '../type-resolver'; -import { scalarToTsType, scalarToFilterType } from '../scalars'; export interface GeneratedInputTypesFile { fileName: string; @@ -122,10 +124,12 @@ function parseTypeString(typeStr: string): t.TSType { const match = typeStr.match(/^([^<]+)<(.+)>$/); if (match) { const [, baseName, params] = match; - const typeParams = params.split(',').map((p) => parseTypeString(p.trim())); + const typeParams = params + .split(',') + .map((p) => parseTypeString(p.trim())); return t.tsTypeReference( t.identifier(baseName), - t.tsTypeParameterInstantiation(typeParams) + t.tsTypeParameterInstantiation(typeParams), ); } } @@ -153,11 +157,11 @@ function parseTypeString(typeStr: string): t.TSType { function createPropertySignature( name: string, typeStr: string, - optional: boolean + optional: boolean, ): t.TSPropertySignature { const prop = t.tsPropertySignature( t.identifier(name), - t.tsTypeAnnotation(parseTypeString(typeStr)) + t.tsTypeAnnotation(parseTypeString(typeStr)), ); prop.optional = optional; return prop; @@ -168,17 +172,17 @@ function createPropertySignature( */ function createExportedInterface( name: string, - properties: Array<{ name: string; type: string; optional: boolean }> + properties: Array<{ name: string; type: string; optional: boolean }>, ): t.ExportNamedDeclaration { const props = properties.map((p) => - createPropertySignature(p.name, p.type, p.optional) + createPropertySignature(p.name, p.type, p.optional), ); const body = t.tsInterfaceBody(props); const interfaceDecl = t.tsInterfaceDeclaration( t.identifier(name), null, null, - body + body, ); return t.exportNamedDeclaration(interfaceDecl); } @@ -188,12 +192,12 @@ function createExportedInterface( */ function createExportedTypeAlias( name: string, - typeStr: string + typeStr: string, ): t.ExportNamedDeclaration { const typeAlias = t.tsTypeAliasDeclaration( t.identifier(name), null, - parseTypeString(typeStr) + parseTypeString(typeStr), ); return t.exportNamedDeclaration(typeAlias); } @@ -202,9 +206,7 @@ function createExportedTypeAlias( * Create a union type from string literals */ function createStringLiteralUnion(values: string[]): t.TSUnionType { - return t.tsUnionType( - values.map((v) => t.tsLiteralType(t.stringLiteral(v))) - ); + return t.tsUnionType(values.map((v) => t.tsLiteralType(t.stringLiteral(v)))); } /** @@ -212,7 +214,7 @@ function createStringLiteralUnion(values: string[]): t.TSUnionType { */ function addSectionComment( statements: t.Statement[], - sectionName: string + sectionName: string, ): void { if (statements.length > 0) { addLineComment(statements[0], `============ ${sectionName} ============`); @@ -328,7 +330,7 @@ const SCALAR_FILTER_CONFIGS: ScalarFilterConfig[] = [ * Build filter properties based on operator sets */ function buildScalarFilterProperties( - config: ScalarFilterConfig + config: ScalarFilterConfig, ): InterfaceProperty[] { const { tsType, operators } = config; const props: InterfaceProperty[] = []; @@ -338,7 +340,7 @@ function buildScalarFilterProperties( props.push( { name: 'isNull', type: 'boolean', optional: true }, { name: 'equalTo', type: tsType, optional: true }, - { name: 'notEqualTo', type: tsType, optional: true } + { name: 'notEqualTo', type: tsType, optional: true }, ); } @@ -346,7 +348,7 @@ function buildScalarFilterProperties( if (operators.includes('distinct')) { props.push( { name: 'distinctFrom', type: tsType, optional: true }, - { name: 'notDistinctFrom', type: tsType, optional: true } + { name: 'notDistinctFrom', type: tsType, optional: true }, ); } @@ -354,7 +356,7 @@ function buildScalarFilterProperties( if (operators.includes('inArray')) { props.push( { name: 'in', type: `${tsType}[]`, optional: true }, - { name: 'notIn', type: `${tsType}[]`, optional: true } + { name: 'notIn', type: `${tsType}[]`, optional: true }, ); } @@ -364,7 +366,7 @@ function buildScalarFilterProperties( { name: 'lessThan', type: tsType, optional: true }, { name: 'lessThanOrEqualTo', type: tsType, optional: true }, { name: 'greaterThan', type: tsType, optional: true }, - { name: 'greaterThanOrEqualTo', type: tsType, optional: true } + { name: 'greaterThanOrEqualTo', type: tsType, optional: true }, ); } @@ -386,7 +388,7 @@ function buildScalarFilterProperties( { name: 'like', type: 'string', optional: true }, { name: 'notLike', type: 'string', optional: true }, { name: 'likeInsensitive', type: 'string', optional: true }, - { name: 'notLikeInsensitive', type: 'string', optional: true } + { name: 'notLikeInsensitive', type: 'string', optional: true }, ); } @@ -397,7 +399,7 @@ function buildScalarFilterProperties( { name: 'containedBy', type: 'Record', optional: true }, { name: 'containsKey', type: 'string', optional: true }, { name: 'containsAllKeys', type: 'string[]', optional: true }, - { name: 'containsAnyKeys', type: 'string[]', optional: true } + { name: 'containsAnyKeys', type: 'string[]', optional: true }, ); } @@ -408,7 +410,7 @@ function buildScalarFilterProperties( { name: 'containsOrEqualTo', type: 'string', optional: true }, { name: 'containedBy', type: 'string', optional: true }, { name: 'containedByOrEqualTo', type: 'string', optional: true }, - { name: 'containsOrContainedBy', type: 'string', optional: true } + { name: 'containsOrContainedBy', type: 'string', optional: true }, ); } @@ -430,7 +432,7 @@ function buildScalarFilterProperties( { name: 'anyLessThan', type: baseType, optional: true }, { name: 'anyLessThanOrEqualTo', type: baseType, optional: true }, { name: 'anyGreaterThan', type: baseType, optional: true }, - { name: 'anyGreaterThanOrEqualTo', type: baseType, optional: true } + { name: 'anyGreaterThanOrEqualTo', type: baseType, optional: true }, ); } @@ -445,7 +447,7 @@ function generateScalarFilterTypes(): t.Statement[] { for (const config of SCALAR_FILTER_CONFIGS) { statements.push( - createExportedInterface(config.name, buildScalarFilterProperties(config)) + createExportedInterface(config.name, buildScalarFilterProperties(config)), ); } @@ -462,7 +464,7 @@ function generateScalarFilterTypes(): t.Statement[] { */ function isLikelyEnumType( typeName: string, - typeRegistry: TypeRegistry + typeRegistry: TypeRegistry, ): boolean { const typeInfo = typeRegistry.get(typeName); return typeInfo?.kind === 'ENUM'; @@ -473,7 +475,7 @@ function isLikelyEnumType( */ function collectEnumTypesFromTables( tables: CleanTable[], - typeRegistry: TypeRegistry + typeRegistry: TypeRegistry, ): Set { const enumTypes = new Set(); @@ -496,7 +498,7 @@ function collectEnumTypesFromTables( */ function generateEnumTypes( typeRegistry: TypeRegistry, - enumTypeNames: Set + enumTypeNames: Set, ): t.Statement[] { if (enumTypeNames.size === 0) return []; @@ -510,7 +512,7 @@ function generateEnumTypes( const typeAlias = t.tsTypeAliasDeclaration( t.identifier(typeName), null, - unionType + unionType, ); statements.push(t.exportNamedDeclaration(typeAlias)); } @@ -558,7 +560,7 @@ function generateEntityTypes(tables: CleanTable[]): t.Statement[] { for (const table of tables) { const { typeName } = getTableNames(table); statements.push( - createExportedInterface(typeName, buildEntityProperties(table)) + createExportedInterface(typeName, buildEntityProperties(table)), ); } @@ -587,11 +589,9 @@ function generateRelationHelperTypes(): t.Statement[] { const connectionResultBody = t.tsInterfaceBody(connectionResultProps); const connectionResultDecl = t.tsInterfaceDeclaration( t.identifier('ConnectionResult'), - t.tsTypeParameterDeclaration([ - t.tsTypeParameter(null, null, 'T'), - ]), + t.tsTypeParameterDeclaration([t.tsTypeParameter(null, null, 'T')]), null, - connectionResultBody + connectionResultBody, ); statements.push(t.exportNamedDeclaration(connectionResultDecl)); @@ -602,7 +602,7 @@ function generateRelationHelperTypes(): t.Statement[] { { name: 'hasPreviousPage', type: 'boolean', optional: false }, { name: 'startCursor', type: 'string | null', optional: true }, { name: 'endCursor', type: 'string | null', optional: true }, - ]) + ]), ); addSectionComment(statements, 'Relation Helper Types'); @@ -615,7 +615,7 @@ function generateRelationHelperTypes(): t.Statement[] { function getRelatedTypeName( tableName: string, - tableByName: Map + tableByName: Map, ): string { const relatedTable = tableByName.get(tableName); return relatedTable ? getTableNames(relatedTable).typeName : tableName; @@ -623,7 +623,7 @@ function getRelatedTypeName( function getRelatedOrderByName( tableName: string, - tableByName: Map + tableByName: Map, ): string { const relatedTable = tableByName.get(tableName); if (relatedTable) { @@ -639,7 +639,7 @@ function getRelatedOrderByName( function getRelatedFilterName( tableName: string, - tableByName: Map + tableByName: Map, ): string { const relatedTable = tableByName.get(tableName); return relatedTable ? getFilterTypeName(relatedTable) : `${tableName}Filter`; @@ -650,7 +650,7 @@ function getRelatedFilterName( */ function buildEntityRelationProperties( table: CleanTable, - tableByName: Map + tableByName: Map, ): InterfaceProperty[] { const properties: InterfaceProperty[] = []; @@ -658,7 +658,7 @@ function buildEntityRelationProperties( if (!relation.fieldName) continue; const relatedTypeName = getRelatedTypeName( relation.referencesTable, - tableByName + tableByName, ); properties.push({ name: relation.fieldName, @@ -671,7 +671,7 @@ function buildEntityRelationProperties( if (!relation.fieldName) continue; const relatedTypeName = getRelatedTypeName( relation.referencedByTable, - tableByName + tableByName, ); properties.push({ name: relation.fieldName, @@ -684,7 +684,7 @@ function buildEntityRelationProperties( if (!relation.fieldName) continue; const relatedTypeName = getRelatedTypeName( relation.referencedByTable, - tableByName + tableByName, ); properties.push({ name: relation.fieldName, @@ -697,7 +697,7 @@ function buildEntityRelationProperties( if (!relation.fieldName) continue; const relatedTypeName = getRelatedTypeName( relation.rightTable, - tableByName + tableByName, ); properties.push({ name: relation.fieldName, @@ -714,7 +714,7 @@ function buildEntityRelationProperties( */ function generateEntityRelationTypes( tables: CleanTable[], - tableByName: Map + tableByName: Map, ): t.Statement[] { const statements: t.Statement[] = []; @@ -723,8 +723,8 @@ function generateEntityRelationTypes( statements.push( createExportedInterface( `${typeName}Relations`, - buildEntityRelationProperties(table, tableByName) - ) + buildEntityRelationProperties(table, tableByName), + ), ); } @@ -745,8 +745,8 @@ function generateEntityWithRelations(tables: CleanTable[]): t.Statement[] { statements.push( createExportedTypeAlias( `${typeName}WithRelations`, - `${typeName} & ${typeName}Relations` - ) + `${typeName} & ${typeName}Relations`, + ), ); } @@ -765,7 +765,7 @@ function generateEntityWithRelations(tables: CleanTable[]): t.Statement[] { */ function buildSelectTypeLiteral( table: CleanTable, - tableByName: Map + tableByName: Map, ): t.TSTypeLiteral { const members: t.TSTypeElement[] = []; @@ -774,7 +774,7 @@ function buildSelectTypeLiteral( if (!isRelationField(field.name, table)) { const prop = t.tsPropertySignature( t.identifier(field.name), - t.tsTypeAnnotation(t.tsBooleanKeyword()) + t.tsTypeAnnotation(t.tsBooleanKeyword()), ); prop.optional = true; members.push(prop); @@ -786,7 +786,7 @@ function buildSelectTypeLiteral( if (relation.fieldName) { const relatedTypeName = getRelatedTypeName( relation.referencesTable, - tableByName + tableByName, ); const prop = t.tsPropertySignature( t.identifier(relation.fieldName), @@ -798,15 +798,15 @@ function buildSelectTypeLiteral( const selectProp = t.tsPropertySignature( t.identifier('select'), t.tsTypeAnnotation( - t.tsTypeReference(t.identifier(`${relatedTypeName}Select`)) - ) + t.tsTypeReference(t.identifier(`${relatedTypeName}Select`)), + ), ); selectProp.optional = true; return selectProp; })(), ]), - ]) - ) + ]), + ), ); prop.optional = true; members.push(prop); @@ -818,15 +818,15 @@ function buildSelectTypeLiteral( if (relation.fieldName) { const relatedTypeName = getRelatedTypeName( relation.referencedByTable, - tableByName + tableByName, ); const filterName = getRelatedFilterName( relation.referencedByTable, - tableByName + tableByName, ); const orderByName = getRelatedOrderByName( relation.referencedByTable, - tableByName + tableByName, ); const prop = t.tsPropertySignature( t.identifier(relation.fieldName), @@ -838,8 +838,8 @@ function buildSelectTypeLiteral( const p = t.tsPropertySignature( t.identifier('select'), t.tsTypeAnnotation( - t.tsTypeReference(t.identifier(`${relatedTypeName}Select`)) - ) + t.tsTypeReference(t.identifier(`${relatedTypeName}Select`)), + ), ); p.optional = true; return p; @@ -847,7 +847,7 @@ function buildSelectTypeLiteral( (() => { const p = t.tsPropertySignature( t.identifier('first'), - t.tsTypeAnnotation(t.tsNumberKeyword()) + t.tsTypeAnnotation(t.tsNumberKeyword()), ); p.optional = true; return p; @@ -855,7 +855,9 @@ function buildSelectTypeLiteral( (() => { const p = t.tsPropertySignature( t.identifier('filter'), - t.tsTypeAnnotation(t.tsTypeReference(t.identifier(filterName))) + t.tsTypeAnnotation( + t.tsTypeReference(t.identifier(filterName)), + ), ); p.optional = true; return p; @@ -864,15 +866,15 @@ function buildSelectTypeLiteral( const p = t.tsPropertySignature( t.identifier('orderBy'), t.tsTypeAnnotation( - t.tsArrayType(t.tsTypeReference(t.identifier(orderByName))) - ) + t.tsArrayType(t.tsTypeReference(t.identifier(orderByName))), + ), ); p.optional = true; return p; })(), ]), - ]) - ) + ]), + ), ); prop.optional = true; members.push(prop); @@ -884,12 +886,12 @@ function buildSelectTypeLiteral( if (relation.fieldName) { const relatedTypeName = getRelatedTypeName( relation.rightTable, - tableByName + tableByName, ); const filterName = getRelatedFilterName(relation.rightTable, tableByName); const orderByName = getRelatedOrderByName( relation.rightTable, - tableByName + tableByName, ); const prop = t.tsPropertySignature( t.identifier(relation.fieldName), @@ -901,8 +903,8 @@ function buildSelectTypeLiteral( const p = t.tsPropertySignature( t.identifier('select'), t.tsTypeAnnotation( - t.tsTypeReference(t.identifier(`${relatedTypeName}Select`)) - ) + t.tsTypeReference(t.identifier(`${relatedTypeName}Select`)), + ), ); p.optional = true; return p; @@ -910,7 +912,7 @@ function buildSelectTypeLiteral( (() => { const p = t.tsPropertySignature( t.identifier('first'), - t.tsTypeAnnotation(t.tsNumberKeyword()) + t.tsTypeAnnotation(t.tsNumberKeyword()), ); p.optional = true; return p; @@ -918,7 +920,9 @@ function buildSelectTypeLiteral( (() => { const p = t.tsPropertySignature( t.identifier('filter'), - t.tsTypeAnnotation(t.tsTypeReference(t.identifier(filterName))) + t.tsTypeAnnotation( + t.tsTypeReference(t.identifier(filterName)), + ), ); p.optional = true; return p; @@ -927,15 +931,15 @@ function buildSelectTypeLiteral( const p = t.tsPropertySignature( t.identifier('orderBy'), t.tsTypeAnnotation( - t.tsArrayType(t.tsTypeReference(t.identifier(orderByName))) - ) + t.tsArrayType(t.tsTypeReference(t.identifier(orderByName))), + ), ); p.optional = true; return p; })(), ]), - ]) - ) + ]), + ), ); prop.optional = true; members.push(prop); @@ -947,7 +951,7 @@ function buildSelectTypeLiteral( if (relation.fieldName) { const relatedTypeName = getRelatedTypeName( relation.referencedByTable, - tableByName + tableByName, ); const prop = t.tsPropertySignature( t.identifier(relation.fieldName), @@ -959,15 +963,15 @@ function buildSelectTypeLiteral( const selectProp = t.tsPropertySignature( t.identifier('select'), t.tsTypeAnnotation( - t.tsTypeReference(t.identifier(`${relatedTypeName}Select`)) - ) + t.tsTypeReference(t.identifier(`${relatedTypeName}Select`)), + ), ); selectProp.optional = true; return selectProp; })(), ]), - ]) - ) + ]), + ), ); prop.optional = true; members.push(prop); @@ -982,7 +986,7 @@ function buildSelectTypeLiteral( */ function generateEntitySelectTypes( tables: CleanTable[], - tableByName: Map + tableByName: Map, ): t.Statement[] { const statements: t.Statement[] = []; @@ -991,7 +995,7 @@ function generateEntitySelectTypes( const typeAlias = t.tsTypeAliasDeclaration( t.identifier(`${typeName}Select`), null, - buildSelectTypeLiteral(table, tableByName) + buildSelectTypeLiteral(table, tableByName), ); statements.push(t.exportNamedDeclaration(typeAlias)); } @@ -1046,7 +1050,7 @@ function generateTableFilterTypes(tables: CleanTable[]): t.Statement[] { for (const table of tables) { const filterName = getFilterTypeName(table); statements.push( - createExportedInterface(filterName, buildTableFilterProperties(table)) + createExportedInterface(filterName, buildTableFilterProperties(table)), ); } @@ -1095,8 +1099,8 @@ function generateTableConditionTypes(tables: CleanTable[]): t.Statement[] { statements.push( createExportedInterface( conditionName, - buildTableConditionProperties(table) - ) + buildTableConditionProperties(table), + ), ); } @@ -1139,7 +1143,7 @@ function generateOrderByTypes(tables: CleanTable[]): t.Statement[] { const typeAlias = t.tsTypeAliasDeclaration( t.identifier(enumName), null, - unionType + unionType, ); statements.push(t.exportNamedDeclaration(typeAlias)); } @@ -1158,14 +1162,14 @@ function generateOrderByTypes(tables: CleanTable[]): t.Statement[] { * Build the nested data object fields for Create input */ function buildCreateDataFields( - table: CleanTable + table: CleanTable, ): Array<{ name: string; type: string; optional: boolean }> { const fields: Array<{ name: string; type: string; optional: boolean }> = []; for (const field of table.fields) { if ( EXCLUDED_MUTATION_FIELDS.includes( - field.name as (typeof EXCLUDED_MUTATION_FIELDS)[number] + field.name as (typeof EXCLUDED_MUTATION_FIELDS)[number], ) ) continue; @@ -1185,7 +1189,9 @@ function buildCreateDataFields( /** * Build Create input interface as AST */ -function buildCreateInputInterface(table: CleanTable): t.ExportNamedDeclaration { +function buildCreateInputInterface( + table: CleanTable, +): t.ExportNamedDeclaration { const { typeName, singularName } = getTableNames(table); const fields = buildCreateDataFields(table); @@ -1193,7 +1199,7 @@ function buildCreateInputInterface(table: CleanTable): t.ExportNamedDeclaration const nestedProps: t.TSPropertySignature[] = fields.map((field) => { const prop = t.tsPropertySignature( t.identifier(field.name), - t.tsTypeAnnotation(parseTypeString(field.type)) + t.tsTypeAnnotation(parseTypeString(field.type)), ); prop.optional = field.optional; return prop; @@ -1206,14 +1212,14 @@ function buildCreateInputInterface(table: CleanTable): t.ExportNamedDeclaration (() => { const prop = t.tsPropertySignature( t.identifier('clientMutationId'), - t.tsTypeAnnotation(t.tsStringKeyword()) + t.tsTypeAnnotation(t.tsStringKeyword()), ); prop.optional = true; return prop; })(), t.tsPropertySignature( t.identifier(singularName), - t.tsTypeAnnotation(nestedObjectType) + t.tsTypeAnnotation(nestedObjectType), ), ]; @@ -1222,7 +1228,7 @@ function buildCreateInputInterface(table: CleanTable): t.ExportNamedDeclaration t.identifier(`Create${typeName}Input`), null, null, - body + body, ); return t.exportNamedDeclaration(interfaceDecl); } @@ -1236,7 +1242,7 @@ function buildPatchProperties(table: CleanTable): InterfaceProperty[] { for (const field of table.fields) { if ( EXCLUDED_MUTATION_FIELDS.includes( - field.name as (typeof EXCLUDED_MUTATION_FIELDS)[number] + field.name as (typeof EXCLUDED_MUTATION_FIELDS)[number], ) ) continue; @@ -1264,29 +1270,34 @@ function generateCrudInputTypes(table: CleanTable): t.Statement[] { const { typeName } = getTableNames(table); const patchName = `${typeName}Patch`; + const pkFields = getPrimaryKeyInfo(table); + const pkField = pkFields[0]; + const pkFieldName = pkField?.name ?? 'id'; + const pkFieldTsType = pkField?.tsType ?? 'string'; + // Create input statements.push(buildCreateInputInterface(table)); // Patch interface statements.push( - createExportedInterface(patchName, buildPatchProperties(table)) + createExportedInterface(patchName, buildPatchProperties(table)), ); // Update input statements.push( createExportedInterface(`Update${typeName}Input`, [ { name: 'clientMutationId', type: 'string', optional: true }, - { name: 'id', type: 'string', optional: false }, + { name: pkFieldName, type: pkFieldTsType, optional: false }, { name: 'patch', type: patchName, optional: false }, - ]) + ]), ); // Delete input statements.push( createExportedInterface(`Delete${typeName}Input`, [ { name: 'clientMutationId', type: 'string', optional: true }, - { name: 'id', type: 'string', optional: false }, - ]) + { name: pkFieldName, type: pkFieldTsType, optional: false }, + ]), ); return statements; @@ -1316,7 +1327,7 @@ function generateAllCrudInputTypes(tables: CleanTable[]): t.Statement[] { * Collect all input type names used by operations */ export function collectInputTypeNames( - operations: Array<{ args: CleanArgument[] }> + operations: Array<{ args: CleanArgument[] }>, ): Set { const inputTypes = new Set(); @@ -1362,7 +1373,7 @@ function buildTableCrudTypeNames(tables: CleanTable[]): Set { function generateCustomInputTypes( typeRegistry: TypeRegistry, usedInputTypes: Set, - tableCrudTypes?: Set + tableCrudTypes?: Set, ): t.Statement[] { const statements: t.Statement[] = []; const generatedTypes = new Set(); @@ -1394,7 +1405,7 @@ function generateCustomInputTypes( addLineComment(commentStmt, ` Type '${typeName}' not found in schema`); statements.push(commentStmt); statements.push( - createExportedTypeAlias(typeName, 'Record') + createExportedTypeAlias(typeName, 'Record'), ); continue; } @@ -1424,7 +1435,7 @@ function generateCustomInputTypes( const typeAlias = t.tsTypeAliasDeclaration( t.identifier(typeName), null, - unionType + unionType, ); statements.push(t.exportNamedDeclaration(typeAlias)); } else { @@ -1450,16 +1461,13 @@ function generateCustomInputTypes( * Collect all payload type names from operation return types */ export function collectPayloadTypeNames( - operations: Array<{ returnType: CleanArgument['type'] }> + operations: Array<{ returnType: CleanArgument['type'] }>, ): Set { const payloadTypes = new Set(); for (const op of operations) { const baseName = getTypeBaseName(op.returnType); - if ( - baseName && - (baseName.endsWith('Payload') || !baseName.endsWith('Connection')) - ) { + if (baseName) { payloadTypes.add(baseName); } } @@ -1473,7 +1481,7 @@ export function collectPayloadTypeNames( function generatePayloadTypes( typeRegistry: TypeRegistry, usedPayloadTypes: Set, - alreadyGeneratedTypes: Set + alreadyGeneratedTypes: Set, ): t.Statement[] { const statements: t.Statement[] = []; const generatedTypes = new Set(alreadyGeneratedTypes); @@ -1558,8 +1566,8 @@ function generatePayloadTypes( const p = t.tsPropertySignature( t.identifier('select'), t.tsTypeAnnotation( - t.tsTypeReference(t.identifier(`${baseType}Select`)) - ) + t.tsTypeReference(t.identifier(`${baseType}Select`)), + ), ); p.optional = true; return p; @@ -1572,7 +1580,7 @@ function generatePayloadTypes( const prop = t.tsPropertySignature( t.identifier(field.name), - t.tsTypeAnnotation(propType) + t.tsTypeAnnotation(propType), ); prop.optional = true; selectMembers.push(prop); @@ -1581,17 +1589,104 @@ function generatePayloadTypes( const selectTypeAlias = t.tsTypeAliasDeclaration( t.identifier(`${typeName}Select`), null, - t.tsTypeLiteral(selectMembers) + t.tsTypeLiteral(selectMembers), ); statements.push(t.exportNamedDeclaration(selectTypeAlias)); } if (statements.length > 0) { - addSectionComment(statements, 'Payload/Return Types (for custom operations)'); + addSectionComment( + statements, + 'Payload/Return Types (for custom operations)', + ); } return statements; } +// ============================================================================ +// Connection Fields Map Generator +// ============================================================================ + +/** + * Generate a runtime map of entity type → { fieldName: relatedTypeName } + * for all hasMany and manyToMany relations. Used by buildSelections() + * to detect connection fields that need `nodes { ... }` wrapping. + */ +function generateConnectionFieldsMap( + tables: CleanTable[], + tableByName: Map, +): t.Statement[] { + const properties: t.ObjectProperty[] = []; + + for (const table of tables) { + const { typeName } = getTableNames(table); + const fieldEntries: t.ObjectProperty[] = []; + + for (const relation of table.relations.hasMany) { + if (!relation.fieldName) continue; + const relatedTypeName = getRelatedTypeName( + relation.referencedByTable, + tableByName, + ); + fieldEntries.push( + t.objectProperty( + t.stringLiteral(relation.fieldName), + t.stringLiteral(relatedTypeName), + ), + ); + } + + for (const relation of table.relations.manyToMany) { + if (!relation.fieldName) continue; + const relatedTypeName = getRelatedTypeName( + relation.rightTable, + tableByName, + ); + fieldEntries.push( + t.objectProperty( + t.stringLiteral(relation.fieldName), + t.stringLiteral(relatedTypeName), + ), + ); + } + + if (fieldEntries.length > 0) { + properties.push( + t.objectProperty( + t.stringLiteral(typeName), + t.objectExpression(fieldEntries), + ), + ); + } + } + + const decl = t.variableDeclaration('const', [ + t.variableDeclarator( + t.identifier('connectionFieldsMap'), + t.tsAsExpression( + t.objectExpression(properties), + t.tsTypeReference( + t.identifier('Record'), + t.tsTypeParameterInstantiation([ + t.tsStringKeyword(), + t.tsTypeReference( + t.identifier('Record'), + t.tsTypeParameterInstantiation([ + t.tsStringKeyword(), + t.tsStringKeyword(), + ]), + ), + ]), + ), + ), + ), + ]); + + const statements: t.Statement[] = [t.exportNamedDeclaration(decl)]; + addSectionComment(statements, 'Connection Fields Map'); + return statements; +} + // ============================================================================ // Main Generator (AST-based) // ============================================================================ @@ -1603,46 +1698,51 @@ export function generateInputTypesFile( typeRegistry: TypeRegistry, usedInputTypes: Set, tables?: CleanTable[], - usedPayloadTypes?: Set + usedPayloadTypes?: Set, ): GeneratedInputTypesFile { const statements: t.Statement[] = []; + const tablesList = tables ?? []; + const hasTables = tablesList.length > 0; + const tableByName = new Map(tablesList.map((table) => [table.name, table])); // 1. Scalar filter types statements.push(...generateScalarFilterTypes()); // 2. Enum types used by table fields - if (tables && tables.length > 0) { - const enumTypes = collectEnumTypesFromTables(tables, typeRegistry); + if (hasTables) { + const enumTypes = collectEnumTypesFromTables(tablesList, typeRegistry); statements.push(...generateEnumTypes(typeRegistry, enumTypes)); } // 3. Entity and relation types (if tables provided) - if (tables && tables.length > 0) { - const tableByName = new Map(tables.map((table) => [table.name, table])); - - statements.push(...generateEntityTypes(tables)); + if (hasTables) { + statements.push(...generateEntityTypes(tablesList)); statements.push(...generateRelationHelperTypes()); - statements.push(...generateEntityRelationTypes(tables, tableByName)); - statements.push(...generateEntityWithRelations(tables)); - statements.push(...generateEntitySelectTypes(tables, tableByName)); + statements.push(...generateEntityRelationTypes(tablesList, tableByName)); + statements.push(...generateEntityWithRelations(tablesList)); + statements.push(...generateEntitySelectTypes(tablesList, tableByName)); // 4. Table filter types - statements.push(...generateTableFilterTypes(tables)); + statements.push(...generateTableFilterTypes(tablesList)); // 4b. Table condition types (simple equality filter) - statements.push(...generateTableConditionTypes(tables)); + statements.push(...generateTableConditionTypes(tablesList)); // 5. OrderBy types - statements.push(...generateOrderByTypes(tables)); + statements.push(...generateOrderByTypes(tablesList)); // 6. CRUD input types - statements.push(...generateAllCrudInputTypes(tables)); + statements.push(...generateAllCrudInputTypes(tablesList)); } + // 6b. Connection fields map (runtime metadata for buildSelections) + // Always emit this export so generated model/custom-op imports stay valid. + statements.push(...generateConnectionFieldsMap(tablesList, tableByName)); + // 7. Custom input types from TypeRegistry const tableCrudTypes = tables ? buildTableCrudTypeNames(tables) : undefined; statements.push( - ...generateCustomInputTypes(typeRegistry, usedInputTypes, tableCrudTypes) + ...generateCustomInputTypes(typeRegistry, usedInputTypes, tableCrudTypes), ); // 8. Payload/return types for custom operations @@ -1658,8 +1758,8 @@ export function generateInputTypesFile( ...generatePayloadTypes( typeRegistry, usedPayloadTypes, - alreadyGeneratedTypes - ) + alreadyGeneratedTypes, + ), ); } diff --git a/graphql/codegen/src/core/codegen/orm/model-generator.ts b/graphql/codegen/src/core/codegen/orm/model-generator.ts index 0498688b4..ddce20029 100644 --- a/graphql/codegen/src/core/codegen/orm/model-generator.ts +++ b/graphql/codegen/src/core/codegen/orm/model-generator.ts @@ -2,16 +2,20 @@ * Model class generator for ORM client (Babel AST-based) * * Generates per-table model classes with findMany, findFirst, create, update, delete methods. + * Each method uses function overloads for IDE autocompletion of select objects. */ -import type { CleanTable } from '../../../types/schema'; import * as t from '@babel/types'; -import { generateCode } from '../babel-ast'; + +import type { CleanTable } from '../../../types/schema'; +import { asConst, generateCode } from '../babel-ast'; import { - getTableNames, - getOrderByTypeName, getFilterTypeName, - lcFirst, getGeneratedFileHeader, + getOrderByTypeName, + getPrimaryKeyInfo, + getTableNames, + hasValidPrimaryKey, + lcFirst, } from '../utils'; export interface GeneratedModelFile { @@ -24,12 +28,15 @@ export interface GeneratedModelFile { function createImportDeclaration( moduleSpecifier: string, namedImports: string[], - typeOnly: boolean = false + typeOnly: boolean = false, ): t.ImportDeclaration { const specifiers = namedImports.map((name) => - t.importSpecifier(t.identifier(name), t.identifier(name)) + t.importSpecifier(t.identifier(name), t.identifier(name)), + ); + const decl = t.importDeclaration( + specifiers, + t.stringLiteral(moduleSpecifier), ); - const decl = t.importDeclaration(specifiers, t.stringLiteral(moduleSpecifier)); decl.importKind = typeOnly ? 'type' : 'value'; return decl; } @@ -39,29 +46,55 @@ function buildMethodBody( args: t.Expression[], operation: string, typeName: string, - fieldName: string + fieldName: string, ): t.Statement[] { const destructureDecl = t.variableDeclaration('const', [ t.variableDeclarator( t.objectPattern([ - t.objectProperty(t.identifier('document'), t.identifier('document'), false, true), - t.objectProperty(t.identifier('variables'), t.identifier('variables'), false, true), + t.objectProperty( + t.identifier('document'), + t.identifier('document'), + false, + true, + ), + t.objectProperty( + t.identifier('variables'), + t.identifier('variables'), + false, + true, + ), ]), - t.callExpression(t.identifier(builderFn), args) + t.callExpression(t.identifier(builderFn), args), ), ]); const returnStmt = t.returnStatement( t.newExpression(t.identifier('QueryBuilder'), [ t.objectExpression([ - t.objectProperty(t.identifier('client'), t.memberExpression(t.thisExpression(), t.identifier('client'))), + t.objectProperty( + t.identifier('client'), + t.memberExpression(t.thisExpression(), t.identifier('client')), + ), t.objectProperty(t.identifier('operation'), t.stringLiteral(operation)), - t.objectProperty(t.identifier('operationName'), t.stringLiteral(typeName)), + t.objectProperty( + t.identifier('operationName'), + t.stringLiteral(typeName), + ), t.objectProperty(t.identifier('fieldName'), t.stringLiteral(fieldName)), - t.objectProperty(t.identifier('document'), t.identifier('document'), false, true), - t.objectProperty(t.identifier('variables'), t.identifier('variables'), false, true), + t.objectProperty( + t.identifier('document'), + t.identifier('document'), + false, + true, + ), + t.objectProperty( + t.identifier('variables'), + t.identifier('variables'), + false, + true, + ), ]), - ]) + ]), ); return [destructureDecl, returnStmt]; @@ -72,32 +105,84 @@ function createClassMethod( typeParameters: t.TSTypeParameterDeclaration | null, params: (t.Identifier | t.TSParameterProperty)[], returnType: t.TSTypeAnnotation | null, - body: t.Statement[] + body: t.Statement[], ): t.ClassMethod { - const method = t.classMethod('method', t.identifier(name), params, t.blockStatement(body)); + const method = t.classMethod( + 'method', + t.identifier(name), + params, + t.blockStatement(body), + ); method.typeParameters = typeParameters; method.returnType = returnType; return method; } -function createConstTypeParam(constraintTypeName: string): t.TSTypeParameterDeclaration { +function createDeclareMethod( + name: string, + typeParameters: t.TSTypeParameterDeclaration | null, + params: (t.Identifier | t.TSParameterProperty)[], + returnType: t.TSTypeAnnotation, +): t.TSDeclareMethod { + const method = t.tsDeclareMethod( + null, + t.identifier(name), + typeParameters, + params, + returnType, + ); + return method; +} + +function createTypeParam( + constraintTypeName: string, + defaultType?: t.TSType, +): t.TSTypeParameterDeclaration { const param = t.tsTypeParameter( t.tsTypeReference(t.identifier(constraintTypeName)), - null, - 'S' + defaultType ?? null, + 'S', ); - (param as any).const = true; return t.tsTypeParameterDeclaration([param]); } +function tsTypeFromPrimitive(typeName: string): t.TSType { + if (typeName === 'string') return t.tsStringKeyword(); + if (typeName === 'number') return t.tsNumberKeyword(); + if (typeName === 'boolean') return t.tsBooleanKeyword(); + return t.tsTypeReference(t.identifier(typeName)); +} + +/** Build a required `select: S` property for overload signatures */ +function requiredSelectProp(): t.TSPropertySignature { + const prop = t.tsPropertySignature( + t.identifier('select'), + t.tsTypeAnnotation(t.tsTypeReference(t.identifier('S'))), + ); + prop.optional = false; + return prop; +} + +/** Build `StrictSelect` type reference for overload intersections */ +function strictSelectGuard(selectTypeName: string): t.TSType { + return t.tsTypeReference( + t.identifier('StrictSelect'), + t.tsTypeParameterInstantiation([ + t.tsTypeReference(t.identifier('S')), + t.tsTypeReference(t.identifier(selectTypeName)), + ]), + ); +} + export function generateModelFile( table: CleanTable, - _useSharedTypes: boolean + _useSharedTypes: boolean, ): GeneratedModelFile { const { typeName, singularName, pluralName } = getTableNames(table); const modelName = `${typeName}Model`; const baseFileName = lcFirst(typeName); - const fileName = baseFileName === 'index' ? `${baseFileName}Model.ts` : `${baseFileName}.ts`; + const fileName = + baseFileName === 'index' ? `${baseFileName}Model.ts` : `${baseFileName}.ts`; const entityLower = singularName; const selectTypeName = `${typeName}Select`; @@ -109,6 +194,8 @@ export function generateModelFile( const deleteInputTypeName = `Delete${typeName}Input`; const patchTypeName = `${typeName}Patch`; + const pkFields = getPrimaryKeyInfo(table); + const pkField = pkFields[0]; const pluralQueryName = table.query?.all ?? pluralName; const createMutationName = table.query?.create ?? `create${typeName}`; const updateMutationName = table.query?.update; @@ -117,242 +204,764 @@ export function generateModelFile( const statements: t.Statement[] = []; statements.push(createImportDeclaration('../client', ['OrmClient'])); - statements.push(createImportDeclaration('../query-builder', [ - 'QueryBuilder', 'buildFindManyDocument', 'buildFindFirstDocument', - 'buildCreateDocument', 'buildUpdateDocument', 'buildDeleteDocument', - ])); - statements.push(createImportDeclaration('../select-types', [ - 'ConnectionResult', 'FindManyArgs', 'FindFirstArgs', 'CreateArgs', - 'UpdateArgs', 'DeleteArgs', 'InferSelectResult', 'DeepExact', - ], true)); - statements.push(createImportDeclaration('../input-types', [ - typeName, relationTypeName, selectTypeName, whereTypeName, orderByTypeName, - createInputTypeName, updateInputTypeName, patchTypeName, - ], true)); + statements.push( + createImportDeclaration('../query-builder', [ + 'QueryBuilder', + 'buildFindManyDocument', + 'buildFindFirstDocument', + 'buildFindOneDocument', + 'buildCreateDocument', + 'buildUpdateByPkDocument', + 'buildDeleteByPkDocument', + ]), + ); + statements.push( + createImportDeclaration( + '../select-types', + [ + 'ConnectionResult', + 'FindManyArgs', + 'FindFirstArgs', + 'CreateArgs', + 'UpdateArgs', + 'DeleteArgs', + 'InferSelectResult', + 'StrictSelect', + ], + true, + ), + ); + statements.push( + createImportDeclaration( + '../input-types', + [ + typeName, + relationTypeName, + selectTypeName, + whereTypeName, + orderByTypeName, + createInputTypeName, + updateInputTypeName, + patchTypeName, + ], + true, + ), + ); + statements.push( + createImportDeclaration('../input-types', ['connectionFieldsMap']), + ); const classBody: t.ClassBody['body'] = []; // Constructor const constructorParam = t.identifier('client'); - constructorParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('OrmClient'))); + constructorParam.typeAnnotation = t.tsTypeAnnotation( + t.tsTypeReference(t.identifier('OrmClient')), + ); const paramProp = t.tsParameterProperty(constructorParam); paramProp.accessibility = 'private'; - classBody.push(t.classMethod('constructor', t.identifier('constructor'), [paramProp], t.blockStatement([]))); - - // findMany method - // Use DeepExact to enforce strict field validation - const findManyParam = t.identifier('args'); - findManyParam.optional = true; - findManyParam.typeAnnotation = t.tsTypeAnnotation( - t.tsTypeReference(t.identifier('FindManyArgs'), t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier('DeepExact'), t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier('S')), - t.tsTypeReference(t.identifier(selectTypeName)), - ])), - t.tsTypeReference(t.identifier(whereTypeName)), - t.tsTypeReference(t.identifier(orderByTypeName)), - ])) + classBody.push( + t.classMethod( + 'constructor', + t.identifier('constructor'), + [paramProp], + t.blockStatement([]), + ), ); - const findManyReturnType = t.tsTypeAnnotation( - t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([ - t.tsTypeLiteral([ - t.tsPropertySignature(t.identifier(pluralQueryName), t.tsTypeAnnotation( - t.tsTypeReference(t.identifier('ConnectionResult'), t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier(relationTypeName)), - t.tsTypeReference(t.identifier('S')), - ])), - ])) - )), + + // Reusable type reference factories + const sRef = () => t.tsTypeReference(t.identifier('S')); + const selectRef = () => t.tsTypeReference(t.identifier(selectTypeName)); + const pkTsType = () => tsTypeFromPrimitive(pkField.tsType); + + // ── findMany ─────────────────────────────────────────────────────────── + { + const argsType = (sel: t.TSType) => + t.tsTypeReference( + t.identifier('FindManyArgs'), + t.tsTypeParameterInstantiation([ + sel, + t.tsTypeReference(t.identifier(whereTypeName)), + t.tsTypeReference(t.identifier(orderByTypeName)), + ]), + ); + const retType = (sel: t.TSType) => + t.tsTypeAnnotation( + t.tsTypeReference( + t.identifier('QueryBuilder'), + t.tsTypeParameterInstantiation([ + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier(pluralQueryName), + t.tsTypeAnnotation( + t.tsTypeReference( + t.identifier('ConnectionResult'), + t.tsTypeParameterInstantiation([ + t.tsTypeReference( + t.identifier('InferSelectResult'), + t.tsTypeParameterInstantiation([ + t.tsTypeReference(t.identifier(relationTypeName)), + sel, + ]), + ), + ]), + ), + ), + ), + ]), + ]), + ), + ); + + // Overload 1: with select (autocompletion) + const o1Param = t.identifier('args'); + o1Param.typeAnnotation = t.tsTypeAnnotation( + t.tsIntersectionType([ + argsType(sRef()), + t.tsTypeLiteral([requiredSelectProp()]), + strictSelectGuard(selectTypeName), ]), - ])) - ); - const findManyArgs = [ - t.stringLiteral(typeName), - t.stringLiteral(pluralQueryName), - t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), - t.objectExpression([ - t.objectProperty(t.identifier('where'), t.optionalMemberExpression(t.identifier('args'), t.identifier('where'), false, true)), - t.objectProperty(t.identifier('orderBy'), t.tsAsExpression( - t.optionalMemberExpression(t.identifier('args'), t.identifier('orderBy'), false, true), - t.tsUnionType([t.tsArrayType(t.tsStringKeyword()), t.tsUndefinedKeyword()]) - )), - t.objectProperty(t.identifier('first'), t.optionalMemberExpression(t.identifier('args'), t.identifier('first'), false, true)), - t.objectProperty(t.identifier('last'), t.optionalMemberExpression(t.identifier('args'), t.identifier('last'), false, true)), - t.objectProperty(t.identifier('after'), t.optionalMemberExpression(t.identifier('args'), t.identifier('after'), false, true)), - t.objectProperty(t.identifier('before'), t.optionalMemberExpression(t.identifier('args'), t.identifier('before'), false, true)), - t.objectProperty(t.identifier('offset'), t.optionalMemberExpression(t.identifier('args'), t.identifier('offset'), false, true)), - ]), - t.stringLiteral(whereTypeName), - t.stringLiteral(orderByTypeName), - ]; - classBody.push(createClassMethod('findMany', createConstTypeParam(selectTypeName), [findManyParam], findManyReturnType, - buildMethodBody('buildFindManyDocument', findManyArgs, 'query', typeName, pluralQueryName))); - - // findFirst method - const findFirstParam = t.identifier('args'); - findFirstParam.optional = true; - findFirstParam.typeAnnotation = t.tsTypeAnnotation( - t.tsTypeReference(t.identifier('FindFirstArgs'), t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier('DeepExact'), t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier('S')), - t.tsTypeReference(t.identifier(selectTypeName)), - ])), - t.tsTypeReference(t.identifier(whereTypeName)), - ])) - ); - const findFirstReturnType = t.tsTypeAnnotation( - t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([ - t.tsTypeLiteral([ - t.tsPropertySignature(t.identifier(pluralQueryName), t.tsTypeAnnotation( - t.tsTypeLiteral([ - t.tsPropertySignature(t.identifier('nodes'), t.tsTypeAnnotation( - t.tsArrayType(t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier(relationTypeName)), - t.tsTypeReference(t.identifier('S')), - ]))) - )), - ]) - )), + ); + classBody.push( + createDeclareMethod( + 'findMany', + createTypeParam(selectTypeName), + [o1Param], + retType(sRef()), + ), + ); + + // Implementation + const implParam = t.identifier('args'); + implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef())); + const selectExpr = t.memberExpression( + t.identifier('args'), + t.identifier('select'), + ); + const bodyArgs = [ + t.stringLiteral(typeName), + t.stringLiteral(pluralQueryName), + selectExpr, + t.objectExpression([ + t.objectProperty( + t.identifier('where'), + t.optionalMemberExpression( + t.identifier('args'), + t.identifier('where'), + false, + true, + ), + ), + t.objectProperty( + t.identifier('orderBy'), + t.tsAsExpression( + t.optionalMemberExpression( + t.identifier('args'), + t.identifier('orderBy'), + false, + true, + ), + t.tsUnionType([ + t.tsArrayType(t.tsStringKeyword()), + t.tsUndefinedKeyword(), + ]), + ), + ), + t.objectProperty( + t.identifier('first'), + t.optionalMemberExpression( + t.identifier('args'), + t.identifier('first'), + false, + true, + ), + ), + t.objectProperty( + t.identifier('last'), + t.optionalMemberExpression( + t.identifier('args'), + t.identifier('last'), + false, + true, + ), + ), + t.objectProperty( + t.identifier('after'), + t.optionalMemberExpression( + t.identifier('args'), + t.identifier('after'), + false, + true, + ), + ), + t.objectProperty( + t.identifier('before'), + t.optionalMemberExpression( + t.identifier('args'), + t.identifier('before'), + false, + true, + ), + ), + t.objectProperty( + t.identifier('offset'), + t.optionalMemberExpression( + t.identifier('args'), + t.identifier('offset'), + false, + true, + ), + ), ]), - ])) - ); - const findFirstArgs = [ - t.stringLiteral(typeName), - t.stringLiteral(pluralQueryName), - t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), - t.objectExpression([ - t.objectProperty(t.identifier('where'), t.optionalMemberExpression(t.identifier('args'), t.identifier('where'), false, true)), - ]), - t.stringLiteral(whereTypeName), - ]; - classBody.push(createClassMethod('findFirst', createConstTypeParam(selectTypeName), [findFirstParam], findFirstReturnType, - buildMethodBody('buildFindFirstDocument', findFirstArgs, 'query', typeName, pluralQueryName))); - - // create method - const createParam = t.identifier('args'); - createParam.typeAnnotation = t.tsTypeAnnotation( - t.tsTypeReference(t.identifier('CreateArgs'), t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier('DeepExact'), t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier('S')), - t.tsTypeReference(t.identifier(selectTypeName)), - ])), - t.tsIndexedAccessType(t.tsTypeReference(t.identifier(createInputTypeName)), t.tsLiteralType(t.stringLiteral(singularName))), - ])) - ); - const createReturnType = t.tsTypeAnnotation( - t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([ + t.stringLiteral(whereTypeName), + t.stringLiteral(orderByTypeName), + t.identifier('connectionFieldsMap'), + ]; + classBody.push( + createClassMethod( + 'findMany', + null, + [implParam], + null, + buildMethodBody( + 'buildFindManyDocument', + bodyArgs, + 'query', + typeName, + pluralQueryName, + ), + ), + ); + } + + // ── findFirst ────────────────────────────────────────────────────────── + { + const argsType = (sel: t.TSType) => + t.tsTypeReference( + t.identifier('FindFirstArgs'), + t.tsTypeParameterInstantiation([ + sel, + t.tsTypeReference(t.identifier(whereTypeName)), + ]), + ); + const retType = (sel: t.TSType) => + t.tsTypeAnnotation( + t.tsTypeReference( + t.identifier('QueryBuilder'), + t.tsTypeParameterInstantiation([ + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier(pluralQueryName), + t.tsTypeAnnotation( + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier('nodes'), + t.tsTypeAnnotation( + t.tsArrayType( + t.tsTypeReference( + t.identifier('InferSelectResult'), + t.tsTypeParameterInstantiation([ + t.tsTypeReference(t.identifier(relationTypeName)), + sel, + ]), + ), + ), + ), + ), + ]), + ), + ), + ]), + ]), + ), + ); + + // Overload 1: with select (autocompletion) + const o1Param = t.identifier('args'); + o1Param.typeAnnotation = t.tsTypeAnnotation( + t.tsIntersectionType([ + argsType(sRef()), + t.tsTypeLiteral([requiredSelectProp()]), + strictSelectGuard(selectTypeName), + ]), + ); + classBody.push( + createDeclareMethod( + 'findFirst', + createTypeParam(selectTypeName), + [o1Param], + retType(sRef()), + ), + ); + + // Implementation + const implParam = t.identifier('args'); + implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef())); + const selectExpr = t.memberExpression( + t.identifier('args'), + t.identifier('select'), + ); + const bodyArgs = [ + t.stringLiteral(typeName), + t.stringLiteral(pluralQueryName), + selectExpr, + t.objectExpression([ + t.objectProperty( + t.identifier('where'), + t.optionalMemberExpression( + t.identifier('args'), + t.identifier('where'), + false, + true, + ), + ), + ]), + t.stringLiteral(whereTypeName), + t.identifier('connectionFieldsMap'), + ]; + classBody.push( + createClassMethod( + 'findFirst', + null, + [implParam], + null, + buildMethodBody( + 'buildFindFirstDocument', + bodyArgs, + 'query', + typeName, + pluralQueryName, + ), + ), + ); + } + + // ── findOne ──────────────────────────────────────────────────────────── + const singleQueryName = table.query?.one; + if (singleQueryName && hasValidPrimaryKey(table)) { + const pkGqlType = pkField.gqlType.replace(/!/g, '') + '!'; + + const retType = (sel: t.TSType) => + t.tsTypeAnnotation( + t.tsTypeReference( + t.identifier('QueryBuilder'), + t.tsTypeParameterInstantiation([ + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier(singleQueryName), + t.tsTypeAnnotation( + t.tsUnionType([ + t.tsTypeReference( + t.identifier('InferSelectResult'), + t.tsTypeParameterInstantiation([ + t.tsTypeReference(t.identifier(relationTypeName)), + sel, + ]), + ), + t.tsNullKeyword(), + ]), + ), + ), + ]), + ]), + ), + ); + + const pkProp = () => { + const prop = t.tsPropertySignature( + t.identifier(pkField.name), + t.tsTypeAnnotation(pkTsType()), + ); + prop.optional = false; + return prop; + }; + + // Overload 1: with select (autocompletion) + const o1Param = t.identifier('args'); + o1Param.typeAnnotation = t.tsTypeAnnotation( + t.tsIntersectionType([ + t.tsTypeLiteral([pkProp(), requiredSelectProp()]), + strictSelectGuard(selectTypeName), + ]), + ); + classBody.push( + createDeclareMethod( + 'findOne', + createTypeParam(selectTypeName), + [o1Param], + retType(sRef()), + ), + ); + + // Implementation + const implParam = t.identifier('args'); + implParam.typeAnnotation = t.tsTypeAnnotation( t.tsTypeLiteral([ - t.tsPropertySignature(t.identifier(createMutationName), t.tsTypeAnnotation( - t.tsTypeLiteral([ - t.tsPropertySignature(t.identifier(entityLower), t.tsTypeAnnotation( - t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier(relationTypeName)), - t.tsTypeReference(t.identifier('S')), - ])) - )), - ]) - )), + pkProp(), + (() => { + const prop = t.tsPropertySignature( + t.identifier('select'), + t.tsTypeAnnotation(t.tsTypeReference(t.identifier(selectTypeName))), + ); + return prop; + })(), ]), - ])) - ); - const createArgs = [ - t.stringLiteral(typeName), - t.stringLiteral(createMutationName), - t.stringLiteral(entityLower), - t.memberExpression(t.identifier('args'), t.identifier('select')), - t.memberExpression(t.identifier('args'), t.identifier('data')), - t.stringLiteral(createInputTypeName), - ]; - classBody.push(createClassMethod('create', createConstTypeParam(selectTypeName), [createParam], createReturnType, - buildMethodBody('buildCreateDocument', createArgs, 'mutation', typeName, createMutationName))); - - // update method (if available) - if (updateMutationName) { - const updateParam = t.identifier('args'); - updateParam.typeAnnotation = t.tsTypeAnnotation( - t.tsTypeReference(t.identifier('UpdateArgs'), t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier('DeepExact'), t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier('S')), - t.tsTypeReference(t.identifier(selectTypeName)), - ])), - t.tsTypeLiteral([t.tsPropertySignature(t.identifier('id'), t.tsTypeAnnotation(t.tsStringKeyword()))]), - t.tsTypeReference(t.identifier(patchTypeName)), - ])) ); - const updateReturnType = t.tsTypeAnnotation( - t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([ - t.tsTypeLiteral([ - t.tsPropertySignature(t.identifier(updateMutationName), t.tsTypeAnnotation( + const selectExpr = t.memberExpression( + t.identifier('args'), + t.identifier('select'), + ); + const bodyArgs = [ + t.stringLiteral(typeName), + t.stringLiteral(singleQueryName), + t.memberExpression(t.identifier('args'), t.identifier(pkField.name)), + selectExpr, + t.stringLiteral(pkField.name), + t.stringLiteral(pkGqlType), + t.identifier('connectionFieldsMap'), + ]; + classBody.push( + createClassMethod( + 'findOne', + null, + [implParam], + null, + buildMethodBody( + 'buildFindOneDocument', + bodyArgs, + 'query', + typeName, + singleQueryName, + ), + ), + ); + } + + // ── create ───────────────────────────────────────────────────────────── + { + const dataType = () => + t.tsIndexedAccessType( + t.tsTypeReference(t.identifier(createInputTypeName)), + t.tsLiteralType(t.stringLiteral(singularName)), + ); + const argsType = (sel: t.TSType) => + t.tsTypeReference( + t.identifier('CreateArgs'), + t.tsTypeParameterInstantiation([sel, dataType()]), + ); + const retType = (sel: t.TSType) => + t.tsTypeAnnotation( + t.tsTypeReference( + t.identifier('QueryBuilder'), + t.tsTypeParameterInstantiation([ t.tsTypeLiteral([ - t.tsPropertySignature(t.identifier(entityLower), t.tsTypeAnnotation( - t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier(relationTypeName)), - t.tsTypeReference(t.identifier('S')), - ])) - )), - ]) - )), + t.tsPropertySignature( + t.identifier(createMutationName), + t.tsTypeAnnotation( + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier(entityLower), + t.tsTypeAnnotation( + t.tsTypeReference( + t.identifier('InferSelectResult'), + t.tsTypeParameterInstantiation([ + t.tsTypeReference(t.identifier(relationTypeName)), + sel, + ]), + ), + ), + ), + ]), + ), + ), + ]), + ]), + ), + ); + + // Overload 1: with select (autocompletion) + const o1Param = t.identifier('args'); + o1Param.typeAnnotation = t.tsTypeAnnotation( + t.tsIntersectionType([ + argsType(sRef()), + t.tsTypeLiteral([requiredSelectProp()]), + strictSelectGuard(selectTypeName), + ]), + ); + classBody.push( + createDeclareMethod( + 'create', + createTypeParam(selectTypeName), + [o1Param], + retType(sRef()), + ), + ); + + // Implementation + const implParam = t.identifier('args'); + implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef())); + const selectExpr = t.memberExpression( + t.identifier('args'), + t.identifier('select'), + ); + const bodyArgs = [ + t.stringLiteral(typeName), + t.stringLiteral(createMutationName), + t.stringLiteral(entityLower), + selectExpr, + t.memberExpression(t.identifier('args'), t.identifier('data')), + t.stringLiteral(createInputTypeName), + t.identifier('connectionFieldsMap'), + ]; + classBody.push( + createClassMethod( + 'create', + null, + [implParam], + null, + buildMethodBody( + 'buildCreateDocument', + bodyArgs, + 'mutation', + typeName, + createMutationName, + ), + ), + ); + } + + // ── update ───────────────────────────────────────────────────────────── + if (updateMutationName) { + const whereLiteral = () => + t.tsTypeLiteral([ + (() => { + const prop = t.tsPropertySignature( + t.identifier(pkField.name), + t.tsTypeAnnotation(pkTsType()), + ); + prop.optional = false; + return prop; + })(), + ]); + const argsType = (sel: t.TSType) => + t.tsTypeReference( + t.identifier('UpdateArgs'), + t.tsTypeParameterInstantiation([ + sel, + whereLiteral(), + t.tsTypeReference(t.identifier(patchTypeName)), ]), - ])) + ); + const retType = (sel: t.TSType) => + t.tsTypeAnnotation( + t.tsTypeReference( + t.identifier('QueryBuilder'), + t.tsTypeParameterInstantiation([ + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier(updateMutationName), + t.tsTypeAnnotation( + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier(entityLower), + t.tsTypeAnnotation( + t.tsTypeReference( + t.identifier('InferSelectResult'), + t.tsTypeParameterInstantiation([ + t.tsTypeReference(t.identifier(relationTypeName)), + sel, + ]), + ), + ), + ), + ]), + ), + ), + ]), + ]), + ), + ); + + // Overload 1: with select (autocompletion) + const o1Param = t.identifier('args'); + o1Param.typeAnnotation = t.tsTypeAnnotation( + t.tsIntersectionType([ + argsType(sRef()), + t.tsTypeLiteral([requiredSelectProp()]), + strictSelectGuard(selectTypeName), + ]), ); - const updateArgs = [ + classBody.push( + createDeclareMethod( + 'update', + createTypeParam(selectTypeName), + [o1Param], + retType(sRef()), + ), + ); + + // Implementation + const implParam = t.identifier('args'); + implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef())); + const selectExpr = t.memberExpression( + t.identifier('args'), + t.identifier('select'), + ); + const bodyArgs = [ t.stringLiteral(typeName), t.stringLiteral(updateMutationName), t.stringLiteral(entityLower), - t.memberExpression(t.identifier('args'), t.identifier('select')), - t.memberExpression(t.identifier('args'), t.identifier('where')), + selectExpr, + t.memberExpression( + t.memberExpression(t.identifier('args'), t.identifier('where')), + t.identifier(pkField.name), + ), t.memberExpression(t.identifier('args'), t.identifier('data')), t.stringLiteral(updateInputTypeName), + t.stringLiteral(pkField.name), + t.identifier('connectionFieldsMap'), ]; - classBody.push(createClassMethod('update', createConstTypeParam(selectTypeName), [updateParam], updateReturnType, - buildMethodBody('buildUpdateDocument', updateArgs, 'mutation', typeName, updateMutationName))); + classBody.push( + createClassMethod( + 'update', + null, + [implParam], + null, + buildMethodBody( + 'buildUpdateByPkDocument', + bodyArgs, + 'mutation', + typeName, + updateMutationName, + ), + ), + ); } - // delete method (if available) + // ── delete ───────────────────────────────────────────────────────────── if (deleteMutationName) { - const deleteParam = t.identifier('args'); - deleteParam.typeAnnotation = t.tsTypeAnnotation( - t.tsTypeReference(t.identifier('DeleteArgs'), t.tsTypeParameterInstantiation([ - t.tsTypeLiteral([t.tsPropertySignature(t.identifier('id'), t.tsTypeAnnotation(t.tsStringKeyword()))]), - ])) - ); - const deleteReturnType = t.tsTypeAnnotation( - t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([ - t.tsTypeLiteral([ - t.tsPropertySignature(t.identifier(deleteMutationName), t.tsTypeAnnotation( + const whereLiteral = () => + t.tsTypeLiteral([ + (() => { + const prop = t.tsPropertySignature( + t.identifier(pkField.name), + t.tsTypeAnnotation(pkTsType()), + ); + prop.optional = false; + return prop; + })(), + ]); + const argsType = (sel: t.TSType) => + t.tsTypeReference( + t.identifier('DeleteArgs'), + t.tsTypeParameterInstantiation([whereLiteral(), sel]), + ); + const retType = (sel: t.TSType) => + t.tsTypeAnnotation( + t.tsTypeReference( + t.identifier('QueryBuilder'), + t.tsTypeParameterInstantiation([ t.tsTypeLiteral([ - t.tsPropertySignature(t.identifier(entityLower), t.tsTypeAnnotation( - t.tsTypeLiteral([t.tsPropertySignature(t.identifier('id'), t.tsTypeAnnotation(t.tsStringKeyword()))]) - )), - ]) - )), - ]), - ])) + t.tsPropertySignature( + t.identifier(deleteMutationName), + t.tsTypeAnnotation( + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier(entityLower), + t.tsTypeAnnotation( + t.tsTypeReference( + t.identifier('InferSelectResult'), + t.tsTypeParameterInstantiation([ + t.tsTypeReference(t.identifier(relationTypeName)), + sel, + ]), + ), + ), + ), + ]), + ), + ), + ]), + ]), + ), + ); + + // Overload 1: with select (autocompletion) + const o1Param = t.identifier('args'); + o1Param.typeAnnotation = t.tsTypeAnnotation( + t.tsIntersectionType([ + argsType(sRef()), + t.tsTypeLiteral([requiredSelectProp()]), + strictSelectGuard(selectTypeName), + ]), + ); + classBody.push( + createDeclareMethod( + 'delete', + createTypeParam(selectTypeName), + [o1Param], + retType(sRef()), + ), + ); + + // Implementation + const implParam = t.identifier('args'); + implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef())); + const selectExpr = t.memberExpression( + t.identifier('args'), + t.identifier('select'), ); - const deleteArgs = [ + const bodyArgs = [ t.stringLiteral(typeName), t.stringLiteral(deleteMutationName), t.stringLiteral(entityLower), - t.memberExpression(t.identifier('args'), t.identifier('where')), + t.memberExpression( + t.memberExpression(t.identifier('args'), t.identifier('where')), + t.identifier(pkField.name), + ), t.stringLiteral(deleteInputTypeName), + t.stringLiteral(pkField.name), + selectExpr, + t.identifier('connectionFieldsMap'), ]; - classBody.push(createClassMethod('delete', null, [deleteParam], deleteReturnType, - buildMethodBody('buildDeleteDocument', deleteArgs, 'mutation', typeName, deleteMutationName))); + classBody.push( + createClassMethod( + 'delete', + null, + [implParam], + null, + buildMethodBody( + 'buildDeleteByPkDocument', + bodyArgs, + 'mutation', + typeName, + deleteMutationName, + ), + ), + ); } - const classDecl = t.classDeclaration(t.identifier(modelName), null, t.classBody(classBody)); + const classDecl = t.classDeclaration( + t.identifier(modelName), + null, + t.classBody(classBody), + ); statements.push(t.exportNamedDeclaration(classDecl)); const header = getGeneratedFileHeader(`${typeName} model for ORM client`); const code = generateCode(statements); - return { fileName, content: header + '\n' + code, modelName, tableName: table.name }; + return { + fileName, + content: header + '\n' + code, + modelName, + tableName: table.name, + }; } export function generateAllModelFiles( tables: CleanTable[], - useSharedTypes: boolean + useSharedTypes: boolean, ): GeneratedModelFile[] { return tables.map((table) => generateModelFile(table, useSharedTypes)); } diff --git a/graphql/codegen/src/core/codegen/orm/select-types.ts b/graphql/codegen/src/core/codegen/orm/select-types.ts index 973b216c3..d03418113 100644 --- a/graphql/codegen/src/core/codegen/orm/select-types.ts +++ b/graphql/codegen/src/core/codegen/orm/select-types.ts @@ -53,16 +53,10 @@ export interface NestedSelectConfig { /** * Recursively validates select objects, rejecting unknown keys. * - * This type ensures that users can only select fields that actually exist - * in the GraphQL schema. It returns `never` if any excess keys are found - * at any nesting level, causing a TypeScript compile error. - * - * Why this is needed: - * TypeScript's excess property checking has a quirk where it only catches - * invalid fields when they are the ONLY fields. When mixed with valid fields - * (e.g., `{ id: true, invalidField: true }`), the structural typing allows - * the excess property through. This type explicitly checks for and rejects - * such cases. + * NOTE: This type is intentionally NOT used in generated parameter positions + * (conditional types block IDE autocompletion). Parameters use `S` directly + * with `S extends XxxSelect` constraints, which provides full + * autocompletion via TypeScript's contextual typing. * * @example * // This will cause a type error because 'invalid' doesn't exist: @@ -79,15 +73,29 @@ export type DeepExact = T extends Shape ? { [K in keyof T]: K extends keyof Shape ? T[K] extends { select: infer NS } - ? Shape[K] extends { select?: infer ShapeNS } - ? { select: DeepExact> } - : T[K] + ? Extract extends { + select?: infer ShapeNS; + } + ? DeepExact< + Omit & { + select: DeepExact>; + }, + Extract + > + : never : T[K] : never; } : never : never; +/** + * Enforces exact select shape while keeping contextual typing on `S extends XxxSelect`. + * Use this as an intersection in overloads: + * `{ select: S } & StrictSelect`. + */ +export type StrictSelect = S extends DeepExact ? {} : never; + /** * Infers the result type from a select configuration * @@ -100,7 +108,9 @@ export type DeepExact = T extends Shape export type InferSelectResult = TSelect extends undefined ? TEntity : { - [K in keyof TSelect as TSelect[K] extends false | undefined ? never : K]: TSelect[K] extends true + [K in keyof TSelect as TSelect[K] extends false | undefined + ? never + : K]: TSelect[K] extends true ? K extends keyof TEntity ? TEntity[K] : never @@ -108,7 +118,9 @@ export type InferSelectResult = TSelect extends undefined ? K extends keyof TEntity ? NonNullable extends ConnectionResult ? ConnectionResult> - : InferSelectResult, NestedSelect> | (null extends TEntity[K] ? null : never) + : + | InferSelectResult, NestedSelect> + | (null extends TEntity[K] ? null : never) : never : K extends keyof TEntity ? TEntity[K] @@ -202,8 +214,9 @@ export interface UpdateArgs { /** * Arguments for delete operations */ -export interface DeleteArgs { +export interface DeleteArgs { where: TWhere; + select?: TSelect; } /** @@ -231,7 +244,11 @@ export type ConnectionQueryResult = QueryResult<{ /** * Type for mutation that returns a payload with the entity */ -export type MutationResult = QueryResult<{ +export type MutationResult< + TEntity, + TSelect, + TPayloadKey extends string, +> = QueryResult<{ [K in TPayloadKey]: { [EntityKey: string]: ResolveSelectResult; }; diff --git a/graphql/codegen/src/core/codegen/queries.ts b/graphql/codegen/src/core/codegen/queries.ts index 55852c339..451370e02 100644 --- a/graphql/codegen/src/core/codegen/queries.ts +++ b/graphql/codegen/src/core/codegen/queries.ts @@ -1,39 +1,69 @@ /** - * Query hook generators using Babel AST-based code generation + * Query hook generators - delegates to ORM model methods (Babel AST-based) * * Output structure: * queries/ - * useCarsQuery.ts - List query hook - * useCarQuery.ts - Single item query hook + * useCarsQuery.ts - List query hook -> ORM findMany + * useCarQuery.ts - Single item query hook -> ORM findOne */ -import type { CleanTable } from '../../types/schema'; import * as t from '@babel/types'; -import { generateCode, addJSDocComment, typedParam, createTypedCallExpression } from './babel-ast'; + +import type { CleanTable } from '../../types/schema'; +import { asConst } from './babel-ast'; import { - buildListQueryAST, - buildSingleQueryAST, - printGraphQL, -} from './gql-ast'; + addJSDocComment, + buildFindManyCallExpr, + buildFindOneCallExpr, + buildListSelectionArgsCall, + buildSelectionArgsCall, + callExpr, + connectionResultType, + constDecl, + createFunctionParam, + createImportDeclaration, + createSAndTDataTypeParams, + createSTypeParam, + createTypeReExport, + destructureParamsWithSelection, + destructureParamsWithSelectionAndScope, + exportAsyncDeclareFunction, + exportAsyncFunction, + exportDeclareFunction, + exportFunction, + generateHookFileCode, + inferSelectResultType, + listQueryResultType, + listSelectionConfigType, + objectProp, + omitType, + returnUseQuery, + scopeTypeLiteral, + selectionConfigType, + singleQueryResultType, + spreadObj, + sRef, + typeRef, + typeLiteralWithProps, + useQueryOptionsType, + useQueryOptionsImplType, + voidStatement, + withFieldsListSelectionType, + withFieldsSelectionType, +} from './hooks-ast'; import { - getTableNames, - getListQueryHookName, - getSingleQueryHookName, - getListQueryFileName, - getSingleQueryFileName, getAllRowsQueryName, - getSingleRowQueryName, getFilterTypeName, - getConditionTypeName, + getListQueryFileName, + getListQueryHookName, getOrderByTypeName, - getScalarFields, - getScalarFilterType, getPrimaryKeyInfo, + getSingleQueryFileName, + getSingleQueryHookName, + getSingleRowQueryName, + getTableNames, hasValidPrimaryKey, - fieldTypeToTs, - toScreamingSnake, - ucFirst, lcFirst, - getGeneratedFileHeader, + ucFirst, } from './utils'; export interface GeneratedQueryFile { @@ -47,611 +77,173 @@ export interface QueryGeneratorOptions { hasRelationships?: boolean; } -function createUnionType(values: string[]): t.TSUnionType { - return t.tsUnionType(values.map((v) => t.tsLiteralType(t.stringLiteral(v)))); -} - -function createFilterInterfaceDeclaration( - name: string, - fieldFilters: Array<{ fieldName: string; filterType: string }>, - isExported: boolean = true -): t.Statement { - const properties: t.TSPropertySignature[] = []; - for (const filter of fieldFilters) { - const prop = t.tsPropertySignature( - t.identifier(filter.fieldName), - t.tsTypeAnnotation(t.tsTypeReference(t.identifier(filter.filterType))) - ); - prop.optional = true; - properties.push(prop); - } - const andProp = t.tsPropertySignature( - t.identifier('and'), - t.tsTypeAnnotation(t.tsArrayType(t.tsTypeReference(t.identifier(name)))) - ); - andProp.optional = true; - properties.push(andProp); - const orProp = t.tsPropertySignature( - t.identifier('or'), - t.tsTypeAnnotation(t.tsArrayType(t.tsTypeReference(t.identifier(name)))) - ); - orProp.optional = true; - properties.push(orProp); - const notProp = t.tsPropertySignature( - t.identifier('not'), - t.tsTypeAnnotation(t.tsTypeReference(t.identifier(name))) - ); - notProp.optional = true; - properties.push(notProp); - const body = t.tsInterfaceBody(properties); - const interfaceDecl = t.tsInterfaceDeclaration( - t.identifier(name), - null, - null, - body - ); - if (isExported) { - return t.exportNamedDeclaration(interfaceDecl); - } - return interfaceDecl; -} - export function generateListQueryHook( table: CleanTable, - options: QueryGeneratorOptions = {} + options: QueryGeneratorOptions = {}, ): GeneratedQueryFile { const { reactQueryEnabled = true, useCentralizedKeys = true, hasRelationships = false, } = options; - const { typeName, pluralName } = getTableNames(table); + const { typeName, pluralName, singularName } = getTableNames(table); const hookName = getListQueryHookName(table); const queryName = getAllRowsQueryName(table); const filterTypeName = getFilterTypeName(table); - const conditionTypeName = getConditionTypeName(table); const orderByTypeName = getOrderByTypeName(table); - const scalarFields = getScalarFields(table); const keysName = `${lcFirst(typeName)}Keys`; const scopeTypeName = `${typeName}Scope`; + const selectTypeName = `${typeName}Select`; + const relationTypeName = `${typeName}WithRelations`; - const queryAST = buildListQueryAST({ table }); - const queryDocument = printGraphQL(queryAST); + const listResultTypeAST = (sel: t.TSType) => + listQueryResultType(queryName, relationTypeName, sel); const statements: t.Statement[] = []; - const filterTypesUsed = new Set(); - for (const field of scalarFields) { - const filterType = getScalarFilterType(field.type.gqlType, field.type.isArray); - if (filterType) { - filterTypesUsed.add(filterType); - } - } - + // Imports if (reactQueryEnabled) { - const reactQueryImport = t.importDeclaration( - [t.importSpecifier(t.identifier('useQuery'), t.identifier('useQuery'))], - t.stringLiteral('@tanstack/react-query') + statements.push( + createImportDeclaration('@tanstack/react-query', ['useQuery']), ); - statements.push(reactQueryImport); - const reactQueryTypeImport = t.importDeclaration( - [ - t.importSpecifier( - t.identifier('UseQueryOptions'), - t.identifier('UseQueryOptions') - ), - t.importSpecifier( - t.identifier('QueryClient'), - t.identifier('QueryClient') - ), - ], - t.stringLiteral('@tanstack/react-query') + statements.push( + createImportDeclaration( + '@tanstack/react-query', + ['UseQueryOptions', 'UseQueryResult', 'QueryClient'], + true, + ), ); - reactQueryTypeImport.importKind = 'type'; - statements.push(reactQueryTypeImport); } - - const clientImport = t.importDeclaration( - [t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], - t.stringLiteral('../client') - ); - statements.push(clientImport); - const clientTypeImport = t.importDeclaration( - [ - t.importSpecifier( - t.identifier('ExecuteOptions'), - t.identifier('ExecuteOptions') - ), - ], - t.stringLiteral('../client') + statements.push(createImportDeclaration('../client', ['getClient'])); + statements.push( + createImportDeclaration('../selection', ['buildListSelectionArgs']), ); - clientTypeImport.importKind = 'type'; - statements.push(clientTypeImport); - - const typesImport = t.importDeclaration( - [ - t.importSpecifier(t.identifier(typeName), t.identifier(typeName)), - ...Array.from(filterTypesUsed).map((ft) => - t.importSpecifier(t.identifier(ft), t.identifier(ft)) - ), - ], - t.stringLiteral('../types') + statements.push( + createImportDeclaration('../selection', ['ListSelectionConfig'], true), ); - typesImport.importKind = 'type'; - statements.push(typesImport); if (useCentralizedKeys) { - const queryKeyImport = t.importDeclaration( - [t.importSpecifier(t.identifier(keysName), t.identifier(keysName))], - t.stringLiteral('../query-keys') - ); - statements.push(queryKeyImport); + statements.push(createImportDeclaration('../query-keys', [keysName])); if (hasRelationships) { - const scopeTypeImport = t.importDeclaration( - [ - t.importSpecifier( - t.identifier(scopeTypeName), - t.identifier(scopeTypeName) - ), - ], - t.stringLiteral('../query-keys') + statements.push( + createImportDeclaration('../query-keys', [scopeTypeName], true), ); - scopeTypeImport.importKind = 'type'; - statements.push(scopeTypeImport); } } - const reExportDecl = t.exportNamedDeclaration( - null, - [t.exportSpecifier(t.identifier(typeName), t.identifier(typeName))], - t.stringLiteral('../types') - ); - reExportDecl.exportKind = 'type'; - statements.push(reExportDecl); - - const queryDocConst = t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier(`${queryName}QueryDocument`), - t.templateLiteral( - [ - t.templateElement( - { raw: '\n' + queryDocument, cooked: '\n' + queryDocument }, - true - ), - ], - [] - ) - ), - ]); - statements.push(t.exportNamedDeclaration(queryDocConst)); - - const fieldFilters = scalarFields - .map((field) => { - const filterType = getScalarFilterType(field.type.gqlType, field.type.isArray); - return filterType ? { fieldName: field.name, filterType } : null; - }) - .filter((f): f is { fieldName: string; filterType: string } => f !== null); - statements.push( - createFilterInterfaceDeclaration(filterTypeName, fieldFilters, false) - ); - - // Generate Condition interface (simple equality filter with scalar types) - // Track non-primitive types (enums) that need to be imported - const enumTypesUsed = new Set(); - const conditionProperties: t.TSPropertySignature[] = scalarFields.map( - (field) => { - const tsType = fieldTypeToTs(field.type); - const isPrimitive = - tsType === 'string' || - tsType === 'number' || - tsType === 'boolean' || - tsType === 'unknown' || - tsType.endsWith('[]'); - let typeAnnotation: t.TSType; - if (field.type.isArray) { - const baseType = tsType.replace('[]', ''); - const isBasePrimitive = - baseType === 'string' || - baseType === 'number' || - baseType === 'boolean' || - baseType === 'unknown'; - if (!isBasePrimitive) { - enumTypesUsed.add(baseType); - } - typeAnnotation = t.tsArrayType( - baseType === 'string' - ? t.tsStringKeyword() - : baseType === 'number' - ? t.tsNumberKeyword() - : baseType === 'boolean' - ? t.tsBooleanKeyword() - : t.tsTypeReference(t.identifier(baseType)) - ); - } else { - if (!isPrimitive) { - enumTypesUsed.add(tsType); - } - typeAnnotation = - tsType === 'string' - ? t.tsStringKeyword() - : tsType === 'number' - ? t.tsNumberKeyword() - : tsType === 'boolean' - ? t.tsBooleanKeyword() - : t.tsTypeReference(t.identifier(tsType)); - } - const prop = t.tsPropertySignature( - t.identifier(field.name), - t.tsTypeAnnotation(typeAnnotation) - ); - prop.optional = true; - return prop; - } - ); - - // Add import for enum types if any are used - if (enumTypesUsed.size > 0) { - const schemaTypesImport = t.importDeclaration( - Array.from(enumTypesUsed).map((et) => - t.importSpecifier(t.identifier(et), t.identifier(et)) - ), - t.stringLiteral('../schema-types') - ); - schemaTypesImport.importKind = 'type'; - statements.push(schemaTypesImport); - } - - const conditionInterface = t.tsInterfaceDeclaration( - t.identifier(conditionTypeName), - null, - null, - t.tsInterfaceBody(conditionProperties) - ); - statements.push(conditionInterface); - - const orderByValues = [ - ...scalarFields.flatMap((f) => [ - `${toScreamingSnake(f.name)}_ASC`, - `${toScreamingSnake(f.name)}_DESC`, - ]), - 'NATURAL', - 'PRIMARY_KEY_ASC', - 'PRIMARY_KEY_DESC', - ]; - const orderByTypeAlias = t.tsTypeAliasDeclaration( - t.identifier(orderByTypeName), - null, - createUnionType(orderByValues) + createImportDeclaration( + '../../orm/input-types', + [selectTypeName, relationTypeName, filterTypeName, orderByTypeName], + true, + ), ); - statements.push(orderByTypeAlias); - - const variablesInterfaceBody = t.tsInterfaceBody([ - (() => { - const p = t.tsPropertySignature( - t.identifier('first'), - t.tsTypeAnnotation(t.tsNumberKeyword()) - ); - p.optional = true; - return p; - })(), - (() => { - const p = t.tsPropertySignature( - t.identifier('last'), - t.tsTypeAnnotation(t.tsNumberKeyword()) - ); - p.optional = true; - return p; - })(), - (() => { - const p = t.tsPropertySignature( - t.identifier('offset'), - t.tsTypeAnnotation(t.tsNumberKeyword()) - ); - p.optional = true; - return p; - })(), - (() => { - const p = t.tsPropertySignature( - t.identifier('before'), - t.tsTypeAnnotation(t.tsStringKeyword()) - ); - p.optional = true; - return p; - })(), - (() => { - const p = t.tsPropertySignature( - t.identifier('after'), - t.tsTypeAnnotation(t.tsStringKeyword()) - ); - p.optional = true; - return p; - })(), - (() => { - const p = t.tsPropertySignature( - t.identifier('filter'), - t.tsTypeAnnotation(t.tsTypeReference(t.identifier(filterTypeName))) - ); - p.optional = true; - return p; - })(), - (() => { - const p = t.tsPropertySignature( - t.identifier('condition'), - t.tsTypeAnnotation(t.tsTypeReference(t.identifier(conditionTypeName))) - ); - p.optional = true; - return p; - })(), - (() => { - const p = t.tsPropertySignature( - t.identifier('orderBy'), - t.tsTypeAnnotation( - t.tsArrayType(t.tsTypeReference(t.identifier(orderByTypeName))) - ) - ); - p.optional = true; - return p; - })(), - ]); - const variablesInterface = t.tsInterfaceDeclaration( - t.identifier(`${ucFirst(pluralName)}QueryVariables`), - null, - null, - variablesInterfaceBody + statements.push( + createImportDeclaration( + '../../orm/select-types', + ['FindManyArgs', 'InferSelectResult', 'ConnectionResult', 'StrictSelect'], + true, + ), ); - statements.push(t.exportNamedDeclaration(variablesInterface)); - const pageInfoType = t.tsTypeLiteral([ - t.tsPropertySignature( - t.identifier('hasNextPage'), - t.tsTypeAnnotation(t.tsBooleanKeyword()) - ), - t.tsPropertySignature( - t.identifier('hasPreviousPage'), - t.tsTypeAnnotation(t.tsBooleanKeyword()) - ), - t.tsPropertySignature( - t.identifier('startCursor'), - t.tsTypeAnnotation( - t.tsUnionType([t.tsStringKeyword(), t.tsNullKeyword()]) - ) - ), - t.tsPropertySignature( - t.identifier('endCursor'), - t.tsTypeAnnotation( - t.tsUnionType([t.tsStringKeyword(), t.tsNullKeyword()]) - ) - ), - ]); - const resultType = t.tsTypeLiteral([ - t.tsPropertySignature( - t.identifier('totalCount'), - t.tsTypeAnnotation(t.tsNumberKeyword()) - ), - t.tsPropertySignature( - t.identifier('nodes'), - t.tsTypeAnnotation( - t.tsArrayType(t.tsTypeReference(t.identifier(typeName))) - ) - ), - t.tsPropertySignature( - t.identifier('pageInfo'), - t.tsTypeAnnotation(pageInfoType) - ), - ]); - const resultInterfaceBody = t.tsInterfaceBody([ - t.tsPropertySignature( - t.identifier(queryName), - t.tsTypeAnnotation(resultType) + // Re-exports + statements.push( + createTypeReExport( + [selectTypeName, relationTypeName, filterTypeName, orderByTypeName], + '../../orm/input-types', ), - ]); - const resultInterface = t.tsInterfaceDeclaration( - t.identifier(`${ucFirst(pluralName)}QueryResult`), - null, - null, - resultInterfaceBody ); - statements.push(t.exportNamedDeclaration(resultInterface)); + // Query key if (useCentralizedKeys) { - const queryKeyConst = t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier(`${queryName}QueryKey`), - t.memberExpression(t.identifier(keysName), t.identifier('list')) - ), - ]); - const queryKeyExport = t.exportNamedDeclaration(queryKeyConst); - addJSDocComment(queryKeyExport, [ + const keyDecl = t.exportNamedDeclaration( + t.variableDeclaration('const', [ + t.variableDeclarator( + t.identifier(`${queryName}QueryKey`), + t.memberExpression(t.identifier(keysName), t.identifier('list')), + ), + ]), + ); + addJSDocComment(keyDecl, [ 'Query key factory - re-exported from query-keys.ts', ]); - statements.push(queryKeyExport); + statements.push(keyDecl); } else { - const queryKeyArrow = t.arrowFunctionExpression( + const keyFn = t.arrowFunctionExpression( [ - typedParam( + createFunctionParam( 'variables', - t.tsTypeReference( - t.identifier(`${ucFirst(pluralName)}QueryVariables`) - ), - true + typeRef('FindManyArgs', [ + t.tsUnknownKeyword(), + typeRef(filterTypeName), + typeRef(orderByTypeName), + ]), + true, ), ], - t.tsAsExpression( + asConst( t.arrayExpression([ t.stringLiteral(typeName.toLowerCase()), t.stringLiteral('list'), t.identifier('variables'), ]), - t.tsTypeReference(t.identifier('const')) - ) + ), ); - const queryKeyConst = t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier(`${queryName}QueryKey`), - queryKeyArrow + statements.push( + t.exportNamedDeclaration( + t.variableDeclaration('const', [ + t.variableDeclarator(t.identifier(`${queryName}QueryKey`), keyFn), + ]), ), - ]); - statements.push(t.exportNamedDeclaration(queryKeyConst)); + ); } - if (reactQueryEnabled) { - const hookBodyStatements: t.Statement[] = []; - if (hasRelationships && useCentralizedKeys) { - hookBodyStatements.push( - t.variableDeclaration('const', [ - t.variableDeclarator( - t.objectPattern([ - t.objectProperty( - t.identifier('scope'), - t.identifier('scope'), - false, - true - ), - t.restElement(t.identifier('queryOptions')), - ]), - t.logicalExpression( - '??', - t.identifier('options'), - t.objectExpression([]) - ) - ), - ]) - ); - hookBodyStatements.push( - t.returnStatement( - t.callExpression(t.identifier('useQuery'), [ - t.objectExpression([ - t.objectProperty( - t.identifier('queryKey'), - t.callExpression( - t.memberExpression( - t.identifier(keysName), - t.identifier('list') - ), - [t.identifier('variables'), t.identifier('scope')] - ) - ), - t.objectProperty( - t.identifier('queryFn'), - t.arrowFunctionExpression( - [], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(`${queryName}QueryDocument`), t.identifier('variables')], - [ - t.tsTypeReference(t.identifier(`${ucFirst(pluralName)}QueryResult`)), - t.tsTypeReference(t.identifier(`${ucFirst(pluralName)}QueryVariables`)), - ] - ) - ) - ), - t.spreadElement(t.identifier('queryOptions')), - ]), - ]) - ) - ); - } else if (useCentralizedKeys) { - hookBodyStatements.push( - t.returnStatement( - t.callExpression(t.identifier('useQuery'), [ - t.objectExpression([ - t.objectProperty( - t.identifier('queryKey'), - t.callExpression( - t.memberExpression( - t.identifier(keysName), - t.identifier('list') - ), - [t.identifier('variables')] - ) - ), - t.objectProperty( - t.identifier('queryFn'), - t.arrowFunctionExpression( - [], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(`${queryName}QueryDocument`), t.identifier('variables')], - [ - t.tsTypeReference(t.identifier(`${ucFirst(pluralName)}QueryResult`)), - t.tsTypeReference(t.identifier(`${ucFirst(pluralName)}QueryVariables`)), - ] - ) - ) - ), - t.spreadElement(t.identifier('options')), - ]), - ]) - ) - ); - } else { - hookBodyStatements.push( - t.returnStatement( - t.callExpression(t.identifier('useQuery'), [ - t.objectExpression([ - t.objectProperty( - t.identifier('queryKey'), - t.callExpression(t.identifier(`${queryName}QueryKey`), [ - t.identifier('variables'), - ]) - ), - t.objectProperty( - t.identifier('queryFn'), - t.arrowFunctionExpression( - [], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(`${queryName}QueryDocument`), t.identifier('variables')], - [ - t.tsTypeReference(t.identifier(`${ucFirst(pluralName)}QueryResult`)), - t.tsTypeReference(t.identifier(`${ucFirst(pluralName)}QueryVariables`)), - ] - ) - ) - ), - t.spreadElement(t.identifier('options')), - ]), - ]) - ) + // Helper for query key call + const buildListQueryKey = ( + argsExpr: t.Expression, + scopeExpr?: t.Expression, + ) => { + if (useCentralizedKeys) { + const args = [argsExpr]; + if (scopeExpr) args.push(scopeExpr); + return callExpr( + t.memberExpression(t.identifier(keysName), t.identifier('list')), + args, ); } + return callExpr(t.identifier(`${queryName}QueryKey`), [argsExpr]); + }; - const hookParams: t.Identifier[] = [ - typedParam( - 'variables', - t.tsTypeReference(t.identifier(`${ucFirst(pluralName)}QueryVariables`)), - true - ), - ]; - let optionsTypeStr: string; + // Helper for findMany queryFn + const buildFindManyFn = () => + t.arrowFunctionExpression([], buildFindManyCallExpr(singularName, 'args')); + + // Options type builder with optional scope + const buildOptionsType = (queryDataType: t.TSType, dataType: t.TSType) => { + const base = omitType( + typeRef('UseQueryOptions', [queryDataType, typeRef('Error'), dataType]), + ['queryKey', 'queryFn'], + ); if (hasRelationships && useCentralizedKeys) { - optionsTypeStr = `Omit, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }`; - } else { - optionsTypeStr = `Omit, 'queryKey' | 'queryFn'>`; + return t.tsIntersectionType([base, scopeTypeLiteral(scopeTypeName)]); } - const optionsParam = t.identifier('options'); - optionsParam.optional = true; - optionsParam.typeAnnotation = t.tsTypeAnnotation( - t.tsTypeReference(t.identifier(optionsTypeStr)) - ); - hookParams.push(optionsParam); + return base; + }; - const hookFunc = t.functionDeclaration( - t.identifier(hookName), - hookParams, - t.blockStatement(hookBodyStatements) - ); - const hookExport = t.exportNamedDeclaration(hookFunc); + // Hook + if (reactQueryEnabled) { const docLines = [ `Query hook for fetching ${typeName} list`, '', '@example', '```tsx', `const { data, isLoading } = ${hookName}({`, - ' first: 10,', - ' filter: { name: { equalTo: "example" } },', - " orderBy: ['CREATED_AT_DESC'],", + ' selection: {', + ' fields: { id: true, name: true },', + ' where: { name: { equalTo: "example" } },', + " orderBy: ['CREATED_AT_DESC'],", + ' first: 10,', + ' },', '});', '```', ]; @@ -659,197 +251,312 @@ export function generateListQueryHook( docLines.push(''); docLines.push('@example With scope for hierarchical cache invalidation'); docLines.push('```tsx'); - docLines.push(`const { data } = ${hookName}(`); - docLines.push(' { first: 10 },'); - docLines.push(" { scope: { parentId: 'parent-id' } }"); - docLines.push(');'); + docLines.push(`const { data } = ${hookName}({`); + docLines.push(' selection: { fields: { id: true }, first: 10 },'); + docLines.push(" scope: { parentId: 'parent-id' },"); + docLines.push('});'); docLines.push('```'); } - addJSDocComment(hookExport, docLines); - statements.push(hookExport); - } - const fetchFuncBody = t.blockStatement([ - t.returnStatement( - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(`${queryName}QueryDocument`), t.identifier('variables'), t.identifier('options')], - [ - t.tsTypeReference(t.identifier(`${ucFirst(pluralName)}QueryResult`)), - t.tsTypeReference(t.identifier(`${ucFirst(pluralName)}QueryVariables`)), - ] - ) - ), - ]); - const fetchFunc = t.functionDeclaration( - t.identifier(`fetch${ucFirst(pluralName)}Query`), - [ - typedParam( - 'variables', - t.tsTypeReference(t.identifier(`${ucFirst(pluralName)}QueryVariables`)), - true - ), - typedParam( - 'options', - t.tsTypeReference(t.identifier('ExecuteOptions')), - true - ), - ], - fetchFuncBody - ); - fetchFunc.async = true; - fetchFunc.returnType = t.tsTypeAnnotation( - t.tsTypeReference( - t.identifier('Promise'), - t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier(`${ucFirst(pluralName)}QueryResult`)), - ]) - ) - ); - const fetchExport = t.exportNamedDeclaration(fetchFunc); - addJSDocComment(fetchExport, [ - `Fetch ${typeName} list without React hooks`, - '', - '@example', - '```ts', - '// Direct fetch', - `const data = await fetch${ucFirst(pluralName)}Query({ first: 10 });`, - '', - '// With QueryClient', - 'const data = await queryClient.fetchQuery({', - ` queryKey: ${queryName}QueryKey(variables),`, - ` queryFn: () => fetch${ucFirst(pluralName)}Query(variables),`, - '});', - '```', - ]); - statements.push(fetchExport); + // Overload 1: with fields + const o1ParamType = t.tsIntersectionType([ + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation( + withFieldsListSelectionType( + sRef(), + selectTypeName, + filterTypeName, + orderByTypeName, + ), + ), + ), + ]), + buildOptionsType(listResultTypeAST(sRef()), typeRef('TData')), + ]); + const o1 = exportDeclareFunction( + hookName, + createSAndTDataTypeParams(selectTypeName, listResultTypeAST(sRef())), + [createFunctionParam('params', o1ParamType)], + typeRef('UseQueryResult', [typeRef('TData')]), + ); + addJSDocComment(o1, docLines); + statements.push(o1); - if (reactQueryEnabled) { - const prefetchParams: t.Identifier[] = [ - typedParam( - 'queryClient', - t.tsTypeReference(t.identifier('QueryClient')) + // Implementation + const implSelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation( + listSelectionConfigType( + typeRef(selectTypeName), + filterTypeName, + orderByTypeName, + ), ), - typedParam( - 'variables', - t.tsTypeReference(t.identifier(`${ucFirst(pluralName)}QueryVariables`)), - true + ); + const implOptionsType = (() => { + const base = useQueryOptionsImplType(); + if (hasRelationships && useCentralizedKeys) { + return t.tsIntersectionType([base, scopeTypeLiteral(scopeTypeName)]); + } + return base; + })(); + const implParamType = t.tsIntersectionType([ + t.tsTypeLiteral([implSelProp]), + implOptionsType, + ]); + + const body: t.Statement[] = []; + body.push( + buildListSelectionArgsCall( + selectTypeName, + filterTypeName, + orderByTypeName, ), - ]; - if (hasRelationships && useCentralizedKeys) { - prefetchParams.push( - typedParam( - 'scope', - t.tsTypeReference(t.identifier(scopeTypeName)), - true - ) - ); - } - prefetchParams.push( - typedParam( - 'options', - t.tsTypeReference(t.identifier('ExecuteOptions')), - true - ) ); - let prefetchQueryKeyExpr: t.Expression; if (hasRelationships && useCentralizedKeys) { - prefetchQueryKeyExpr = t.callExpression( - t.memberExpression(t.identifier(keysName), t.identifier('list')), - [t.identifier('variables'), t.identifier('scope')] - ); - } else if (useCentralizedKeys) { - prefetchQueryKeyExpr = t.callExpression( - t.memberExpression(t.identifier(keysName), t.identifier('list')), - [t.identifier('variables')] + body.push(destructureParamsWithSelectionAndScope('queryOptions')); + body.push(voidStatement('_selection')); + body.push( + returnUseQuery( + buildListQueryKey(t.identifier('args'), t.identifier('scope')), + buildFindManyFn(), + [spreadObj(t.identifier('queryOptions'))], + ), ); } else { - prefetchQueryKeyExpr = t.callExpression( - t.identifier(`${queryName}QueryKey`), - [t.identifier('variables')] + body.push(destructureParamsWithSelection('queryOptions')); + body.push(voidStatement('_selection')); + body.push( + returnUseQuery( + buildListQueryKey(t.identifier('args')), + buildFindManyFn(), + [spreadObj(t.identifier('queryOptions'))], + ), ); } - const prefetchFuncBody = t.blockStatement([ - t.expressionStatement( - t.awaitExpression( - t.callExpression( - t.memberExpression( - t.identifier('queryClient'), - t.identifier('prefetchQuery') - ), - [ - t.objectExpression([ - t.objectProperty( - t.identifier('queryKey'), - prefetchQueryKeyExpr - ), - t.objectProperty( - t.identifier('queryFn'), - t.arrowFunctionExpression( - [], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(`${queryName}QueryDocument`), t.identifier('variables'), t.identifier('options')], - [ - t.tsTypeReference(t.identifier(`${ucFirst(pluralName)}QueryResult`)), - t.tsTypeReference(t.identifier(`${ucFirst(pluralName)}QueryVariables`)), - ] - ) - ) - ), - ]), - ] - ) - ) + statements.push( + exportFunction( + hookName, + null, + [createFunctionParam('params', implParamType)], + body, + ), + ); + } + + // Fetch function + const fetchFnName = `fetch${ucFirst(pluralName)}Query`; + { + // Overload 1: with fields + const f1ParamType = t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation( + withFieldsListSelectionType( + sRef(), + selectTypeName, + filterTypeName, + orderByTypeName, + ), + ), ), ]); + const f1Decl = exportAsyncDeclareFunction( + fetchFnName, + createSTypeParam(selectTypeName), + [createFunctionParam('params', f1ParamType)], + typeRef('Promise', [listResultTypeAST(sRef())]), + ); + addJSDocComment(f1Decl, [ + `Fetch ${typeName} list without React hooks`, + '', + '@example', + '```ts', + `const data = await ${fetchFnName}({`, + ' selection: {', + ' fields: { id: true },', + ' first: 10,', + ' },', + '});', + '```', + ]); + statements.push(f1Decl); - const prefetchFunc = t.functionDeclaration( - t.identifier(`prefetch${ucFirst(pluralName)}Query`), - prefetchParams, - prefetchFuncBody + // Implementation + const fImplParamType = t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation( + listSelectionConfigType( + typeRef(selectTypeName), + filterTypeName, + orderByTypeName, + ), + ), + ), + ]); + const fBody: t.Statement[] = []; + fBody.push( + buildListSelectionArgsCall( + selectTypeName, + filterTypeName, + orderByTypeName, + ), ); - prefetchFunc.async = true; - prefetchFunc.returnType = t.tsTypeAnnotation( - t.tsTypeReference( - t.identifier('Promise'), - t.tsTypeParameterInstantiation([t.tsVoidKeyword()]) - ) + fBody.push(t.returnStatement(buildFindManyCallExpr(singularName, 'args'))); + statements.push( + exportAsyncFunction( + fetchFnName, + null, + [createFunctionParam('params', fImplParamType)], + fBody, + ), ); - const prefetchExport = t.exportNamedDeclaration(prefetchFunc); - addJSDocComment(prefetchExport, [ + } + + // Prefetch function + if (reactQueryEnabled) { + const prefetchFnName = `prefetch${ucFirst(pluralName)}Query`; + + // Overload 1: with fields + const p1Params: t.TSPropertySignature[] = [ + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation( + withFieldsListSelectionType( + sRef(), + selectTypeName, + filterTypeName, + orderByTypeName, + ), + ), + ), + ]; + const p1ParamType = + hasRelationships && useCentralizedKeys + ? t.tsIntersectionType([ + t.tsTypeLiteral(p1Params), + scopeTypeLiteral(scopeTypeName), + ]) + : t.tsTypeLiteral(p1Params); + const p1Decl = exportAsyncDeclareFunction( + prefetchFnName, + createSTypeParam(selectTypeName), + [ + createFunctionParam('queryClient', typeRef('QueryClient')), + createFunctionParam('params', p1ParamType), + ], + typeRef('Promise', [t.tsVoidKeyword()]), + ); + addJSDocComment(p1Decl, [ `Prefetch ${typeName} list for SSR or cache warming`, '', '@example', '```ts', - `await prefetch${ucFirst(pluralName)}Query(queryClient, { first: 10 });`, + `await ${prefetchFnName}(queryClient, { selection: { fields: { id: true }, first: 10 } });`, '```', ]); - statements.push(prefetchExport); + statements.push(p1Decl); + + // Implementation + const pImplParamType = + hasRelationships && useCentralizedKeys + ? t.tsIntersectionType([ + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation( + listSelectionConfigType( + typeRef(selectTypeName), + filterTypeName, + orderByTypeName, + ), + ), + ), + ]), + scopeTypeLiteral(scopeTypeName), + ]) + : t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation( + listSelectionConfigType( + typeRef(selectTypeName), + filterTypeName, + orderByTypeName, + ), + ), + ), + ]); + const pBody: t.Statement[] = []; + pBody.push( + buildListSelectionArgsCall( + selectTypeName, + filterTypeName, + orderByTypeName, + ), + ); + + const queryKeyExpr = + hasRelationships && useCentralizedKeys + ? buildListQueryKey( + t.identifier('args'), + t.optionalMemberExpression( + t.identifier('params'), + t.identifier('scope'), + false, + true, + ), + ) + : buildListQueryKey(t.identifier('args')); + + const prefetchCall = callExpr( + t.memberExpression( + t.identifier('queryClient'), + t.identifier('prefetchQuery'), + ), + [ + t.objectExpression([ + objectProp('queryKey', queryKeyExpr), + objectProp('queryFn', buildFindManyFn()), + ]), + ], + ); + pBody.push(t.expressionStatement(t.awaitExpression(prefetchCall))); + + statements.push( + exportAsyncFunction( + prefetchFnName, + null, + [ + createFunctionParam('queryClient', typeRef('QueryClient')), + createFunctionParam('params', pImplParamType), + ], + pBody, + typeRef('Promise', [t.tsVoidKeyword()]), + ), + ); } - const code = generateCode(statements); const headerText = reactQueryEnabled ? `List query hook for ${typeName}` : `List query functions for ${typeName}`; - const content = getGeneratedFileHeader(headerText) + '\n\n' + code; return { fileName: getListQueryFileName(table), - content, + content: generateHookFileCode(headerText, statements), }; } export function generateSingleQueryHook( table: CleanTable, - options: QueryGeneratorOptions = {} + options: QueryGeneratorOptions = {}, ): GeneratedQueryFile | null { - // Skip tables with composite keys - they are handled as custom queries - if (!hasValidPrimaryKey(table)) { - return null; - } + if (!hasValidPrimaryKey(table)) return null; const { reactQueryEnabled = true, @@ -861,535 +568,449 @@ export function generateSingleQueryHook( const queryName = getSingleRowQueryName(table); const keysName = `${lcFirst(typeName)}Keys`; const scopeTypeName = `${typeName}Scope`; + const selectTypeName = `${typeName}Select`; + const relationTypeName = `${typeName}WithRelations`; const pkFields = getPrimaryKeyInfo(table); const pkField = pkFields[0]; - const pkName = pkField.name; - const pkTsType = pkField.tsType; + const pkFieldName = pkField?.name ?? 'id'; + const pkFieldTsType = pkField?.tsType ?? 'string'; - const queryAST = buildSingleQueryAST({ table }); - const queryDocument = printGraphQL(queryAST); + const pkTsType: t.TSType = + pkFieldTsType === 'string' ? t.tsStringKeyword() : t.tsNumberKeyword(); + const singleResultTypeAST = (sel: t.TSType) => + singleQueryResultType(queryName, relationTypeName, sel); const statements: t.Statement[] = []; + // Imports if (reactQueryEnabled) { - const reactQueryImport = t.importDeclaration( - [t.importSpecifier(t.identifier('useQuery'), t.identifier('useQuery'))], - t.stringLiteral('@tanstack/react-query') + statements.push( + createImportDeclaration('@tanstack/react-query', ['useQuery']), ); - statements.push(reactQueryImport); - const reactQueryTypeImport = t.importDeclaration( - [ - t.importSpecifier( - t.identifier('UseQueryOptions'), - t.identifier('UseQueryOptions') - ), - t.importSpecifier( - t.identifier('QueryClient'), - t.identifier('QueryClient') - ), - ], - t.stringLiteral('@tanstack/react-query') + statements.push( + createImportDeclaration( + '@tanstack/react-query', + ['UseQueryOptions', 'UseQueryResult', 'QueryClient'], + true, + ), ); - reactQueryTypeImport.importKind = 'type'; - statements.push(reactQueryTypeImport); } - - const clientImport = t.importDeclaration( - [t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], - t.stringLiteral('../client') - ); - statements.push(clientImport); - const clientTypeImport = t.importDeclaration( - [ - t.importSpecifier( - t.identifier('ExecuteOptions'), - t.identifier('ExecuteOptions') - ), - ], - t.stringLiteral('../client') + statements.push(createImportDeclaration('../client', ['getClient'])); + statements.push( + createImportDeclaration('../selection', ['buildSelectionArgs']), ); - clientTypeImport.importKind = 'type'; - statements.push(clientTypeImport); - - const typesImport = t.importDeclaration( - [t.importSpecifier(t.identifier(typeName), t.identifier(typeName))], - t.stringLiteral('../types') + statements.push( + createImportDeclaration('../selection', ['SelectionConfig'], true), ); - typesImport.importKind = 'type'; - statements.push(typesImport); if (useCentralizedKeys) { - const queryKeyImport = t.importDeclaration( - [t.importSpecifier(t.identifier(keysName), t.identifier(keysName))], - t.stringLiteral('../query-keys') - ); - statements.push(queryKeyImport); + statements.push(createImportDeclaration('../query-keys', [keysName])); if (hasRelationships) { - const scopeTypeImport = t.importDeclaration( - [ - t.importSpecifier( - t.identifier(scopeTypeName), - t.identifier(scopeTypeName) - ), - ], - t.stringLiteral('../query-keys') + statements.push( + createImportDeclaration('../query-keys', [scopeTypeName], true), ); - scopeTypeImport.importKind = 'type'; - statements.push(scopeTypeImport); } } - const reExportDecl = t.exportNamedDeclaration( - null, - [t.exportSpecifier(t.identifier(typeName), t.identifier(typeName))], - t.stringLiteral('../types') - ); - reExportDecl.exportKind = 'type'; - statements.push(reExportDecl); - - const queryDocConst = t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier(`${queryName}QueryDocument`), - t.templateLiteral( - [ - t.templateElement( - { raw: '\n' + queryDocument, cooked: '\n' + queryDocument }, - true - ), - ], - [] - ) + statements.push( + createImportDeclaration( + '../../orm/input-types', + [selectTypeName, relationTypeName], + true, ), - ]); - statements.push(t.exportNamedDeclaration(queryDocConst)); - - const pkTypeAnnotation = - pkTsType === 'string' - ? t.tsStringKeyword() - : pkTsType === 'number' - ? t.tsNumberKeyword() - : t.tsTypeReference(t.identifier(pkTsType)); - - const variablesInterfaceBody = t.tsInterfaceBody([ - t.tsPropertySignature( - t.identifier(pkName), - t.tsTypeAnnotation(pkTypeAnnotation) + ); + statements.push( + createImportDeclaration( + '../../orm/select-types', + ['InferSelectResult', 'StrictSelect'], + true, ), - ]); - const variablesInterface = t.tsInterfaceDeclaration( - t.identifier(`${ucFirst(singularName)}QueryVariables`), - null, - null, - variablesInterfaceBody ); - statements.push(t.exportNamedDeclaration(variablesInterface)); - const resultInterfaceBody = t.tsInterfaceBody([ - t.tsPropertySignature( - t.identifier(queryName), - t.tsTypeAnnotation( - t.tsUnionType([ - t.tsTypeReference(t.identifier(typeName)), - t.tsNullKeyword(), - ]) - ) + // Re-exports + statements.push( + createTypeReExport( + [selectTypeName, relationTypeName], + '../../orm/input-types', ), - ]); - const resultInterface = t.tsInterfaceDeclaration( - t.identifier(`${ucFirst(singularName)}QueryResult`), - null, - null, - resultInterfaceBody ); - statements.push(t.exportNamedDeclaration(resultInterface)); + // Query key if (useCentralizedKeys) { - const queryKeyConst = t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier(`${queryName}QueryKey`), - t.memberExpression(t.identifier(keysName), t.identifier('detail')) - ), - ]); - const queryKeyExport = t.exportNamedDeclaration(queryKeyConst); - addJSDocComment(queryKeyExport, [ + const keyDecl = t.exportNamedDeclaration( + t.variableDeclaration('const', [ + t.variableDeclarator( + t.identifier(`${queryName}QueryKey`), + t.memberExpression(t.identifier(keysName), t.identifier('detail')), + ), + ]), + ); + addJSDocComment(keyDecl, [ 'Query key factory - re-exported from query-keys.ts', ]); - statements.push(queryKeyExport); + statements.push(keyDecl); } else { - const queryKeyArrow = t.arrowFunctionExpression( - [typedParam(pkName, pkTypeAnnotation)], - t.tsAsExpression( + const keyFn = t.arrowFunctionExpression( + [createFunctionParam('id', pkTsType)], + asConst( t.arrayExpression([ t.stringLiteral(typeName.toLowerCase()), t.stringLiteral('detail'), - t.identifier(pkName), + t.identifier('id'), ]), - t.tsTypeReference(t.identifier('const')) - ) + ), ); - const queryKeyConst = t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier(`${queryName}QueryKey`), - queryKeyArrow + statements.push( + t.exportNamedDeclaration( + t.variableDeclaration('const', [ + t.variableDeclarator(t.identifier(`${queryName}QueryKey`), keyFn), + ]), ), - ]); - statements.push(t.exportNamedDeclaration(queryKeyConst)); + ); } - if (reactQueryEnabled) { - const hookBodyStatements: t.Statement[] = []; - if (hasRelationships && useCentralizedKeys) { - hookBodyStatements.push( - t.variableDeclaration('const', [ - t.variableDeclarator( - t.objectPattern([ - t.objectProperty( - t.identifier('scope'), - t.identifier('scope'), - false, - true - ), - t.restElement(t.identifier('queryOptions')), - ]), - t.logicalExpression( - '??', - t.identifier('options'), - t.objectExpression([]) - ) - ), - ]) - ); - hookBodyStatements.push( - t.returnStatement( - t.callExpression(t.identifier('useQuery'), [ - t.objectExpression([ - t.objectProperty( - t.identifier('queryKey'), - t.callExpression( - t.memberExpression( - t.identifier(keysName), - t.identifier('detail') - ), - [ - t.memberExpression( - t.identifier('variables'), - t.identifier(pkName) - ), - t.identifier('scope'), - ] - ) - ), - t.objectProperty( - t.identifier('queryFn'), - t.arrowFunctionExpression( - [], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(`${queryName}QueryDocument`), t.identifier('variables')], - [ - t.tsTypeReference(t.identifier(`${ucFirst(singularName)}QueryResult`)), - t.tsTypeReference(t.identifier(`${ucFirst(singularName)}QueryVariables`)), - ] - ) - ) - ), - t.spreadElement(t.identifier('queryOptions')), - ]), - ]) - ) - ); - } else if (useCentralizedKeys) { - hookBodyStatements.push( - t.returnStatement( - t.callExpression(t.identifier('useQuery'), [ - t.objectExpression([ - t.objectProperty( - t.identifier('queryKey'), - t.callExpression( - t.memberExpression( - t.identifier(keysName), - t.identifier('detail') - ), - [ - t.memberExpression( - t.identifier('variables'), - t.identifier(pkName) - ), - ] - ) - ), - t.objectProperty( - t.identifier('queryFn'), - t.arrowFunctionExpression( - [], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(`${queryName}QueryDocument`), t.identifier('variables')], - [ - t.tsTypeReference(t.identifier(`${ucFirst(singularName)}QueryResult`)), - t.tsTypeReference(t.identifier(`${ucFirst(singularName)}QueryVariables`)), - ] - ) - ) - ), - t.spreadElement(t.identifier('options')), - ]), - ]) - ) - ); - } else { - hookBodyStatements.push( - t.returnStatement( - t.callExpression(t.identifier('useQuery'), [ - t.objectExpression([ - t.objectProperty( - t.identifier('queryKey'), - t.callExpression(t.identifier(`${queryName}QueryKey`), [ - t.memberExpression( - t.identifier('variables'), - t.identifier(pkName) - ), - ]) - ), - t.objectProperty( - t.identifier('queryFn'), - t.arrowFunctionExpression( - [], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(`${queryName}QueryDocument`), t.identifier('variables')], - [ - t.tsTypeReference(t.identifier(`${ucFirst(singularName)}QueryResult`)), - t.tsTypeReference(t.identifier(`${ucFirst(singularName)}QueryVariables`)), - ] - ) - ) - ), - t.spreadElement(t.identifier('options')), - ]), - ]) - ) + // Helper for query key call + const buildDetailQueryKey = ( + pkExpr: t.Expression, + scopeExpr?: t.Expression, + ) => { + if (useCentralizedKeys) { + const args = [pkExpr]; + if (scopeExpr) args.push(scopeExpr); + return callExpr( + t.memberExpression(t.identifier(keysName), t.identifier('detail')), + args, ); } + return callExpr(t.identifier(`${queryName}QueryKey`), [pkExpr]); + }; - const hookParams: t.Identifier[] = [ - typedParam( - 'variables', - t.tsTypeReference(t.identifier(`${ucFirst(singularName)}QueryVariables`)) - ), - ]; - let optionsTypeStr: string; - if (hasRelationships && useCentralizedKeys) { - optionsTypeStr = `Omit, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }`; - } else { - optionsTypeStr = `Omit, 'queryKey' | 'queryFn'>`; - } - const optionsParam = t.identifier('options'); - optionsParam.optional = true; - optionsParam.typeAnnotation = t.tsTypeAnnotation( - t.tsTypeReference(t.identifier(optionsTypeStr)) + // Helper for findOne queryFn + const buildFindOneFn = () => + t.arrowFunctionExpression( + [], + buildFindOneCallExpr(singularName, pkFieldName, 'args'), ); - hookParams.push(optionsParam); - const hookFunc = t.functionDeclaration( - t.identifier(hookName), - hookParams, - t.blockStatement(hookBodyStatements) + // Options type builder with optional scope + const buildSingleOptionsType = ( + queryDataType: t.TSType, + dataType: t.TSType, + ) => { + const base = omitType( + typeRef('UseQueryOptions', [queryDataType, typeRef('Error'), dataType]), + ['queryKey', 'queryFn'], ); - const hookExport = t.exportNamedDeclaration(hookFunc); + if (hasRelationships && useCentralizedKeys) { + return t.tsIntersectionType([base, scopeTypeLiteral(scopeTypeName)]); + } + return base; + }; + + // Hook + if (reactQueryEnabled) { const docLines = [ `Query hook for fetching a single ${typeName}`, '', '@example', '```tsx', - `const { data, isLoading } = ${hookName}({ ${pkName}: 'some-id' });`, + `const { data, isLoading } = ${hookName}({`, + ` ${pkFieldName}: 'some-id',`, + ' selection: { fields: { id: true, name: true } },', + '});', '```', ]; if (hasRelationships && useCentralizedKeys) { docLines.push(''); docLines.push('@example With scope for hierarchical cache invalidation'); docLines.push('```tsx'); - docLines.push(`const { data } = ${hookName}(`); - docLines.push(` { ${pkName}: 'some-id' },`); - docLines.push(" { scope: { parentId: 'parent-id' } }"); - docLines.push(');'); + docLines.push(`const { data } = ${hookName}({`); + docLines.push(` ${pkFieldName}: 'some-id',`); + docLines.push(' selection: { fields: { id: true } },'); + docLines.push(" scope: { parentId: 'parent-id' },"); + docLines.push('});'); docLines.push('```'); } - addJSDocComment(hookExport, docLines); - statements.push(hookExport); - } - const fetchFuncBody = t.blockStatement([ - t.returnStatement( - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(`${queryName}QueryDocument`), t.identifier('variables'), t.identifier('options')], - [ - t.tsTypeReference(t.identifier(`${ucFirst(singularName)}QueryResult`)), - t.tsTypeReference(t.identifier(`${ucFirst(singularName)}QueryVariables`)), - ] - ) - ), - ]); - const fetchFunc = t.functionDeclaration( - t.identifier(`fetch${ucFirst(singularName)}Query`), - [ - typedParam( - 'variables', - t.tsTypeReference(t.identifier(`${ucFirst(singularName)}QueryVariables`)) + // Overload 1: with fields + const o1Props = [ + t.tsPropertySignature( + t.identifier(pkFieldName), + t.tsTypeAnnotation(pkTsType), ), - typedParam( - 'options', - t.tsTypeReference(t.identifier('ExecuteOptions')), - true + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(withFieldsSelectionType(sRef(), selectTypeName)), ), - ], - fetchFuncBody - ); - fetchFunc.async = true; - fetchFunc.returnType = t.tsTypeAnnotation( - t.tsTypeReference( - t.identifier('Promise'), - t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier(`${ucFirst(singularName)}QueryResult`)), - ]) - ) - ); - const fetchExport = t.exportNamedDeclaration(fetchFunc); - addJSDocComment(fetchExport, [ - `Fetch a single ${typeName} without React hooks`, - '', - '@example', - '```ts', - `const data = await fetch${ucFirst(singularName)}Query({ ${pkName}: 'some-id' });`, - '```', - ]); - statements.push(fetchExport); + ]; + const o1ParamType = t.tsIntersectionType([ + t.tsTypeLiteral(o1Props), + buildSingleOptionsType(singleResultTypeAST(sRef()), typeRef('TData')), + ]); + const o1 = exportDeclareFunction( + hookName, + createSAndTDataTypeParams(selectTypeName, singleResultTypeAST(sRef())), + [createFunctionParam('params', o1ParamType)], + typeRef('UseQueryResult', [typeRef('TData')]), + ); + addJSDocComment(o1, docLines); + statements.push(o1); - if (reactQueryEnabled) { - const prefetchParams: t.Identifier[] = [ - typedParam( - 'queryClient', - t.tsTypeReference(t.identifier('QueryClient')) + // Implementation + const implProps = [ + t.tsPropertySignature( + t.identifier(pkFieldName), + t.tsTypeAnnotation(pkTsType), ), - typedParam( - 'variables', - t.tsTypeReference(t.identifier(`${ucFirst(singularName)}QueryVariables`)) + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName))), ), ]; - if (hasRelationships && useCentralizedKeys) { - prefetchParams.push( - typedParam( - 'scope', - t.tsTypeReference(t.identifier(scopeTypeName)), - true - ) - ); - } - prefetchParams.push( - typedParam( - 'options', - t.tsTypeReference(t.identifier('ExecuteOptions')), - true - ) + const implOptionsType = (() => { + const base = useQueryOptionsImplType(); + if (hasRelationships && useCentralizedKeys) { + return t.tsIntersectionType([base, scopeTypeLiteral(scopeTypeName)]); + } + return base; + })(); + const implParamType = t.tsIntersectionType([ + t.tsTypeLiteral(implProps), + implOptionsType, + ]); + + const body: t.Statement[] = []; + body.push(buildSelectionArgsCall(selectTypeName)); + + const pkMemberExpr = t.memberExpression( + t.identifier('params'), + t.identifier(pkFieldName), ); - let prefetchQueryKeyExpr: t.Expression; if (hasRelationships && useCentralizedKeys) { - prefetchQueryKeyExpr = t.callExpression( - t.memberExpression(t.identifier(keysName), t.identifier('detail')), - [ - t.memberExpression(t.identifier('variables'), t.identifier(pkName)), - t.identifier('scope'), - ] - ); - } else if (useCentralizedKeys) { - prefetchQueryKeyExpr = t.callExpression( - t.memberExpression(t.identifier(keysName), t.identifier('detail')), - [t.memberExpression(t.identifier('variables'), t.identifier(pkName))] + body.push(destructureParamsWithSelectionAndScope('queryOptions')); + body.push(voidStatement('_selection')); + body.push( + returnUseQuery( + buildDetailQueryKey(pkMemberExpr, t.identifier('scope')), + buildFindOneFn(), + [spreadObj(t.identifier('queryOptions'))], + ), ); } else { - prefetchQueryKeyExpr = t.callExpression( - t.identifier(`${queryName}QueryKey`), - [t.memberExpression(t.identifier('variables'), t.identifier(pkName))] + body.push(destructureParamsWithSelection('queryOptions')); + body.push(voidStatement('_selection')); + body.push( + returnUseQuery(buildDetailQueryKey(pkMemberExpr), buildFindOneFn(), [ + spreadObj(t.identifier('queryOptions')), + ]), ); } - const prefetchFuncBody = t.blockStatement([ - t.expressionStatement( - t.awaitExpression( - t.callExpression( - t.memberExpression( - t.identifier('queryClient'), - t.identifier('prefetchQuery') - ), - [ - t.objectExpression([ - t.objectProperty( - t.identifier('queryKey'), - prefetchQueryKeyExpr - ), - t.objectProperty( - t.identifier('queryFn'), - t.arrowFunctionExpression( - [], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(`${queryName}QueryDocument`), t.identifier('variables'), t.identifier('options')], - [ - t.tsTypeReference(t.identifier(`${ucFirst(singularName)}QueryResult`)), - t.tsTypeReference(t.identifier(`${ucFirst(singularName)}QueryVariables`)), - ] - ) - ) - ), - ]), - ] - ) - ) + statements.push( + exportFunction( + hookName, + null, + [createFunctionParam('params', implParamType)], + body, + ), + ); + } + + // Fetch function + const fetchFnName = `fetch${ucFirst(singularName)}Query`; + { + // Overload 1: with fields + const f1Props = [ + t.tsPropertySignature( + t.identifier(pkFieldName), + t.tsTypeAnnotation(pkTsType), + ), + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(withFieldsSelectionType(sRef(), selectTypeName)), ), + ]; + const f1Decl = exportAsyncDeclareFunction( + fetchFnName, + createSTypeParam(selectTypeName), + [createFunctionParam('params', t.tsTypeLiteral(f1Props))], + typeRef('Promise', [singleResultTypeAST(sRef())]), + ); + addJSDocComment(f1Decl, [ + `Fetch a single ${typeName} without React hooks`, + '', + '@example', + '```ts', + `const data = await ${fetchFnName}({`, + ` ${pkFieldName}: 'some-id',`, + ' selection: { fields: { id: true } },', + '});', + '```', ]); + statements.push(f1Decl); - const prefetchFunc = t.functionDeclaration( - t.identifier(`prefetch${ucFirst(singularName)}Query`), - prefetchParams, - prefetchFuncBody + // Implementation + const fBody: t.Statement[] = []; + fBody.push(buildSelectionArgsCall(selectTypeName)); + fBody.push( + t.returnStatement( + buildFindOneCallExpr(singularName, pkFieldName, 'args'), + ), + ); + const fImplProps = [ + t.tsPropertySignature( + t.identifier(pkFieldName), + t.tsTypeAnnotation(pkTsType), + ), + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName))), + ), + ]; + statements.push( + exportAsyncFunction( + fetchFnName, + null, + [createFunctionParam('params', t.tsTypeLiteral(fImplProps))], + fBody, + ), ); - prefetchFunc.async = true; - prefetchFunc.returnType = t.tsTypeAnnotation( - t.tsTypeReference( - t.identifier('Promise'), - t.tsTypeParameterInstantiation([t.tsVoidKeyword()]) - ) + } + + // Prefetch function + if (reactQueryEnabled) { + const prefetchFnName = `prefetch${ucFirst(singularName)}Query`; + + // Overload 1: with fields + const p1Props: t.TSPropertySignature[] = [ + t.tsPropertySignature( + t.identifier(pkFieldName), + t.tsTypeAnnotation(pkTsType), + ), + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(withFieldsSelectionType(sRef(), selectTypeName)), + ), + ]; + const p1ParamType = + hasRelationships && useCentralizedKeys + ? t.tsIntersectionType([ + t.tsTypeLiteral(p1Props), + scopeTypeLiteral(scopeTypeName), + ]) + : t.tsTypeLiteral(p1Props); + const p1Decl = exportAsyncDeclareFunction( + prefetchFnName, + createSTypeParam(selectTypeName), + [ + createFunctionParam('queryClient', typeRef('QueryClient')), + createFunctionParam('params', p1ParamType), + ], + typeRef('Promise', [t.tsVoidKeyword()]), ); - const prefetchExport = t.exportNamedDeclaration(prefetchFunc); - addJSDocComment(prefetchExport, [ + addJSDocComment(p1Decl, [ `Prefetch a single ${typeName} for SSR or cache warming`, '', '@example', '```ts', - `await prefetch${ucFirst(singularName)}Query(queryClient, { ${pkName}: 'some-id' });`, + `await ${prefetchFnName}(queryClient, { ${pkFieldName}: 'some-id', selection: { fields: { id: true } } });`, '```', ]); - statements.push(prefetchExport); + statements.push(p1Decl); + + // Implementation + const pImplParamType = + hasRelationships && useCentralizedKeys + ? t.tsIntersectionType([ + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier(pkFieldName), + t.tsTypeAnnotation(pkTsType), + ), + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName))), + ), + ]), + scopeTypeLiteral(scopeTypeName), + ]) + : t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier(pkFieldName), + t.tsTypeAnnotation(pkTsType), + ), + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName))), + ), + ]); + const pBody: t.Statement[] = []; + pBody.push(buildSelectionArgsCall(selectTypeName)); + + const queryKeyExpr = + hasRelationships && useCentralizedKeys + ? buildDetailQueryKey( + t.memberExpression( + t.identifier('params'), + t.identifier(pkFieldName), + ), + t.optionalMemberExpression( + t.identifier('params'), + t.identifier('scope'), + false, + true, + ), + ) + : buildDetailQueryKey( + t.memberExpression( + t.identifier('params'), + t.identifier(pkFieldName), + ), + ); + + const prefetchCall = callExpr( + t.memberExpression( + t.identifier('queryClient'), + t.identifier('prefetchQuery'), + ), + [ + t.objectExpression([ + objectProp('queryKey', queryKeyExpr), + objectProp('queryFn', buildFindOneFn()), + ]), + ], + ); + pBody.push(t.expressionStatement(t.awaitExpression(prefetchCall))); + + statements.push( + exportAsyncFunction( + prefetchFnName, + null, + [ + createFunctionParam('queryClient', typeRef('QueryClient')), + createFunctionParam('params', pImplParamType), + ], + pBody, + typeRef('Promise', [t.tsVoidKeyword()]), + ), + ); } - const code = generateCode(statements); const headerText = reactQueryEnabled ? `Single item query hook for ${typeName}` : `Single item query functions for ${typeName}`; - const content = getGeneratedFileHeader(headerText) + '\n\n' + code; return { fileName: getSingleQueryFileName(table), - content, + content: generateHookFileCode(headerText, statements), }; } export function generateAllQueryHooks( tables: CleanTable[], - options: QueryGeneratorOptions = {} + options: QueryGeneratorOptions = {}, ): GeneratedQueryFile[] { const files: GeneratedQueryFile[] = []; for (const table of tables) { diff --git a/graphql/codegen/src/core/codegen/query-keys.ts b/graphql/codegen/src/core/codegen/query-keys.ts index 791d4eec6..9447cb1e4 100644 --- a/graphql/codegen/src/core/codegen/query-keys.ts +++ b/graphql/codegen/src/core/codegen/query-keys.ts @@ -10,17 +10,22 @@ */ import * as t from '@babel/types'; -import type { CleanTable, CleanOperation } from '../../types/schema'; -import type { QueryKeyConfig, EntityRelationship } from '../../types/config'; -import { getTableNames, getGeneratedFileHeader, ucFirst, lcFirst } from './utils'; +import type { EntityRelationship, QueryKeyConfig } from '../../types/config'; +import type { CleanOperation, CleanTable } from '../../types/schema'; import { - generateCode, addJSDocComment, asConst, constArray, - typedParam, + generateCode, keyofTypeof, + typedParam, } from './babel-ast'; +import { + getGeneratedFileHeader, + getTableNames, + lcFirst, + ucFirst, +} from './utils'; export interface QueryKeyGeneratorOptions { tables: CleanTable[]; @@ -38,7 +43,7 @@ export interface GeneratedQueryKeysFile { */ function getAncestors( entityName: string, - relationships: Record + relationships: Record, ): string[] { const relationship = relationships[entityName.toLowerCase()]; if (!relationship) return []; @@ -62,7 +67,7 @@ function getAncestors( */ function generateScopeTypeDeclaration( entityName: string, - relationships: Record + relationships: Record, ): t.ExportNamedDeclaration | null { const relationship = relationships[entityName.toLowerCase()]; if (!relationship) return null; @@ -80,7 +85,7 @@ function generateScopeTypeDeclaration( fkField = rel.foreignKey; } else { const directRel = Object.entries(relationships).find( - ([, r]) => r.parent === parent + ([, r]) => r.parent === parent, ); if (directRel) { fkField = directRel[1].foreignKey; @@ -89,7 +94,7 @@ function generateScopeTypeDeclaration( const signature = t.tsPropertySignature( t.identifier(fkField), - t.tsTypeAnnotation(t.tsStringKeyword()) + t.tsTypeAnnotation(t.tsStringKeyword()), ); signature.optional = true; members.push(signature); @@ -99,18 +104,21 @@ function generateScopeTypeDeclaration( t.tsTypeAliasDeclaration( t.identifier(typeName), null, - t.tsTypeLiteral(members) - ) + t.tsTypeLiteral(members), + ), ); } /** * Build the 'all' property: all: ['entityKey'] as const */ -function buildAllProperty(entityKey: string, singularName: string): t.ObjectProperty { +function buildAllProperty( + entityKey: string, + singularName: string, +): t.ObjectProperty { const prop = t.objectProperty( t.identifier('all'), - constArray([t.stringLiteral(entityKey)]) + constArray([t.stringLiteral(entityKey)]), ); addJSDocComment(prop, [`All ${singularName} queries`]); return prop; @@ -123,7 +131,7 @@ function buildByParentProperty( entityKey: string, typeName: string, parent: string, - fkField: string + fkField: string, ): t.ObjectProperty { const parentUpper = ucFirst(parent); const parentLower = lcFirst(parent); @@ -133,16 +141,20 @@ function buildByParentProperty( constArray([ t.stringLiteral(entityKey), t.objectExpression([ - t.objectProperty(t.identifier(fkField), t.identifier(fkField), false, true) - ]) - ]) + t.objectProperty( + t.identifier(fkField), + t.identifier(fkField), + false, + true, + ), + ]), + ]), ); - const prop = t.objectProperty( - t.identifier(`by${parentUpper}`), - arrowFn - ); - addJSDocComment(prop, [`${typeName} queries scoped to a specific ${parentLower}`]); + const prop = t.objectProperty(t.identifier(`by${parentUpper}`), arrowFn); + addJSDocComment(prop, [ + `${typeName} queries scoped to a specific ${parentLower}`, + ]); return prop; } @@ -153,10 +165,14 @@ function buildScopedProperty( keysName: string, typeName: string, relationship: EntityRelationship, - ancestors: string[] + ancestors: string[], ): t.ObjectProperty { const scopeTypeName = `${typeName}Scope`; - const scopeParam = typedParam('scope', t.tsTypeReference(t.identifier(scopeTypeName)), true); + const scopeParam = typedParam( + 'scope', + t.tsTypeReference(t.identifier(scopeTypeName)), + true, + ); const statements: t.Statement[] = []; @@ -167,20 +183,25 @@ function buildScopedProperty( t.identifier('scope'), t.identifier(relationship.foreignKey), false, - true + true, ), t.blockStatement([ t.returnStatement( t.callExpression( t.memberExpression( t.identifier(keysName), - t.identifier(`by${ucFirst(relationship.parent)}`) + t.identifier(`by${ucFirst(relationship.parent)}`), ), - [t.memberExpression(t.identifier('scope'), t.identifier(relationship.foreignKey))] - ) - ) - ]) - ) + [ + t.memberExpression( + t.identifier('scope'), + t.identifier(relationship.foreignKey), + ), + ], + ), + ), + ]), + ), ); } @@ -193,32 +214,37 @@ function buildScopedProperty( t.identifier('scope'), t.identifier(fkField), false, - true + true, ), t.blockStatement([ t.returnStatement( t.callExpression( t.memberExpression( t.identifier(keysName), - t.identifier(`by${ucFirst(ancestor)}`) + t.identifier(`by${ucFirst(ancestor)}`), ), - [t.memberExpression(t.identifier('scope'), t.identifier(fkField))] - ) - ) - ]) - ) + [ + t.memberExpression( + t.identifier('scope'), + t.identifier(fkField), + ), + ], + ), + ), + ]), + ), ); } statements.push( t.returnStatement( - t.memberExpression(t.identifier(keysName), t.identifier('all')) - ) + t.memberExpression(t.identifier(keysName), t.identifier('all')), + ), ); const arrowFn = t.arrowFunctionExpression( [scopeParam], - t.blockStatement(statements) + t.blockStatement(statements), ); const prop = t.objectProperty(t.identifier('scoped'), arrowFn); @@ -229,8 +255,15 @@ function buildScopedProperty( /** * Build lists property (scoped version) */ -function buildScopedListsProperty(keysName: string, scopeTypeName: string): t.ObjectProperty { - const scopeParam = typedParam('scope', t.tsTypeReference(t.identifier(scopeTypeName)), true); +function buildScopedListsProperty( + keysName: string, + scopeTypeName: string, +): t.ObjectProperty { + const scopeParam = typedParam( + 'scope', + t.tsTypeReference(t.identifier(scopeTypeName)), + true, + ); const arrowFn = t.arrowFunctionExpression( [scopeParam], @@ -238,11 +271,11 @@ function buildScopedListsProperty(keysName: string, scopeTypeName: string): t.Ob t.spreadElement( t.callExpression( t.memberExpression(t.identifier(keysName), t.identifier('scoped')), - [t.identifier('scope')] - ) + [t.identifier('scope')], + ), ), - t.stringLiteral('list') - ]) + t.stringLiteral('list'), + ]), ); const prop = t.objectProperty(t.identifier('lists'), arrowFn); @@ -253,9 +286,20 @@ function buildScopedListsProperty(keysName: string, scopeTypeName: string): t.Ob /** * Build list property (scoped version) */ -function buildScopedListProperty(keysName: string, scopeTypeName: string): t.ObjectProperty { - const variablesParam = typedParam('variables', t.tsTypeReference(t.identifier('object')), true); - const scopeParam = typedParam('scope', t.tsTypeReference(t.identifier(scopeTypeName)), true); +function buildScopedListProperty( + keysName: string, + scopeTypeName: string, +): t.ObjectProperty { + const variablesParam = typedParam( + 'variables', + t.tsTypeReference(t.identifier('object')), + true, + ); + const scopeParam = typedParam( + 'scope', + t.tsTypeReference(t.identifier(scopeTypeName)), + true, + ); const arrowFn = t.arrowFunctionExpression( [variablesParam, scopeParam], @@ -263,11 +307,11 @@ function buildScopedListProperty(keysName: string, scopeTypeName: string): t.Obj t.spreadElement( t.callExpression( t.memberExpression(t.identifier(keysName), t.identifier('lists')), - [t.identifier('scope')] - ) + [t.identifier('scope')], + ), ), - t.identifier('variables') - ]) + t.identifier('variables'), + ]), ); const prop = t.objectProperty(t.identifier('list'), arrowFn); @@ -278,8 +322,15 @@ function buildScopedListProperty(keysName: string, scopeTypeName: string): t.Obj /** * Build details property (scoped version) */ -function buildScopedDetailsProperty(keysName: string, scopeTypeName: string): t.ObjectProperty { - const scopeParam = typedParam('scope', t.tsTypeReference(t.identifier(scopeTypeName)), true); +function buildScopedDetailsProperty( + keysName: string, + scopeTypeName: string, +): t.ObjectProperty { + const scopeParam = typedParam( + 'scope', + t.tsTypeReference(t.identifier(scopeTypeName)), + true, + ); const arrowFn = t.arrowFunctionExpression( [scopeParam], @@ -287,11 +338,11 @@ function buildScopedDetailsProperty(keysName: string, scopeTypeName: string): t. t.spreadElement( t.callExpression( t.memberExpression(t.identifier(keysName), t.identifier('scoped')), - [t.identifier('scope')] - ) + [t.identifier('scope')], + ), ), - t.stringLiteral('detail') - ]) + t.stringLiteral('detail'), + ]), ); const prop = t.objectProperty(t.identifier('details'), arrowFn); @@ -302,9 +353,19 @@ function buildScopedDetailsProperty(keysName: string, scopeTypeName: string): t. /** * Build detail property (scoped version) */ -function buildScopedDetailProperty(keysName: string, scopeTypeName: string): t.ObjectProperty { - const idParam = typedParam('id', t.tsUnionType([t.tsStringKeyword(), t.tsNumberKeyword()])); - const scopeParam = typedParam('scope', t.tsTypeReference(t.identifier(scopeTypeName)), true); +function buildScopedDetailProperty( + keysName: string, + scopeTypeName: string, +): t.ObjectProperty { + const idParam = typedParam( + 'id', + t.tsUnionType([t.tsStringKeyword(), t.tsNumberKeyword()]), + ); + const scopeParam = typedParam( + 'scope', + t.tsTypeReference(t.identifier(scopeTypeName)), + true, + ); const arrowFn = t.arrowFunctionExpression( [idParam, scopeParam], @@ -312,11 +373,11 @@ function buildScopedDetailProperty(keysName: string, scopeTypeName: string): t.O t.spreadElement( t.callExpression( t.memberExpression(t.identifier(keysName), t.identifier('details')), - [t.identifier('scope')] - ) + [t.identifier('scope')], + ), ), - t.identifier('id') - ]) + t.identifier('id'), + ]), ); const prop = t.objectProperty(t.identifier('detail'), arrowFn); @@ -331,9 +392,11 @@ function buildSimpleListsProperty(keysName: string): t.ObjectProperty { const arrowFn = t.arrowFunctionExpression( [], constArray([ - t.spreadElement(t.memberExpression(t.identifier(keysName), t.identifier('all'))), - t.stringLiteral('list') - ]) + t.spreadElement( + t.memberExpression(t.identifier(keysName), t.identifier('all')), + ), + t.stringLiteral('list'), + ]), ); const prop = t.objectProperty(t.identifier('lists'), arrowFn); @@ -345,7 +408,11 @@ function buildSimpleListsProperty(keysName: string): t.ObjectProperty { * Build simple (non-scoped) list property */ function buildSimpleListProperty(keysName: string): t.ObjectProperty { - const variablesParam = typedParam('variables', t.tsTypeReference(t.identifier('object')), true); + const variablesParam = typedParam( + 'variables', + t.tsTypeReference(t.identifier('object')), + true, + ); const arrowFn = t.arrowFunctionExpression( [variablesParam], @@ -353,11 +420,11 @@ function buildSimpleListProperty(keysName: string): t.ObjectProperty { t.spreadElement( t.callExpression( t.memberExpression(t.identifier(keysName), t.identifier('lists')), - [] - ) + [], + ), ), - t.identifier('variables') - ]) + t.identifier('variables'), + ]), ); const prop = t.objectProperty(t.identifier('list'), arrowFn); @@ -372,9 +439,11 @@ function buildSimpleDetailsProperty(keysName: string): t.ObjectProperty { const arrowFn = t.arrowFunctionExpression( [], constArray([ - t.spreadElement(t.memberExpression(t.identifier(keysName), t.identifier('all'))), - t.stringLiteral('detail') - ]) + t.spreadElement( + t.memberExpression(t.identifier(keysName), t.identifier('all')), + ), + t.stringLiteral('detail'), + ]), ); const prop = t.objectProperty(t.identifier('details'), arrowFn); @@ -386,7 +455,10 @@ function buildSimpleDetailsProperty(keysName: string): t.ObjectProperty { * Build simple (non-scoped) detail property */ function buildSimpleDetailProperty(keysName: string): t.ObjectProperty { - const idParam = typedParam('id', t.tsUnionType([t.tsStringKeyword(), t.tsNumberKeyword()])); + const idParam = typedParam( + 'id', + t.tsUnionType([t.tsStringKeyword(), t.tsNumberKeyword()]), + ); const arrowFn = t.arrowFunctionExpression( [idParam], @@ -394,11 +466,11 @@ function buildSimpleDetailProperty(keysName: string): t.ObjectProperty { t.spreadElement( t.callExpression( t.memberExpression(t.identifier(keysName), t.identifier('details')), - [] - ) + [], + ), ), - t.identifier('id') - ]) + t.identifier('id'), + ]), ); const prop = t.objectProperty(t.identifier('detail'), arrowFn); @@ -412,7 +484,7 @@ function buildSimpleDetailProperty(keysName: string): t.ObjectProperty { function generateEntityKeysDeclaration( table: CleanTable, relationships: Record, - generateScopedKeys: boolean + generateScopedKeys: boolean, ): t.ExportNamedDeclaration { const { typeName, singularName } = getTableNames(table); const entityKey = typeName.toLowerCase(); @@ -434,10 +506,14 @@ function generateEntityKeysDeclaration( if (relationship.parent === parent) { fkField = relationship.foreignKey; } - properties.push(buildByParentProperty(entityKey, typeName, parent, fkField)); + properties.push( + buildByParentProperty(entityKey, typeName, parent, fkField), + ); } - properties.push(buildScopedProperty(keysName, typeName, relationship, ancestors)); + properties.push( + buildScopedProperty(keysName, typeName, relationship, ancestors), + ); const scopeTypeName = `${typeName}Scope`; properties.push(buildScopedListsProperty(keysName, scopeTypeName)); @@ -455,9 +531,9 @@ function generateEntityKeysDeclaration( t.variableDeclaration('const', [ t.variableDeclarator( t.identifier(keysName), - asConst(t.objectExpression(properties)) - ) - ]) + asConst(t.objectExpression(properties)), + ), + ]), ); } @@ -465,7 +541,7 @@ function generateEntityKeysDeclaration( * Generate query keys declaration for custom operations */ function generateCustomQueryKeysDeclaration( - operations: CleanOperation[] + operations: CleanOperation[], ): t.ExportNamedDeclaration | null { if (operations.length === 0) return null; @@ -473,25 +549,27 @@ function generateCustomQueryKeysDeclaration( for (const op of operations) { const hasArgs = op.args.length > 0; - const hasRequiredArgs = op.args.some( - (arg) => arg.type.kind === 'NON_NULL' - ); + const hasRequiredArgs = op.args.some((arg) => arg.type.kind === 'NON_NULL'); let prop: t.ObjectProperty; if (hasArgs) { - const variablesParam = typedParam('variables', t.tsTypeReference(t.identifier('object')), !hasRequiredArgs); + const variablesParam = typedParam( + 'variables', + t.tsTypeReference(t.identifier('object')), + !hasRequiredArgs, + ); const arrowFn = t.arrowFunctionExpression( [variablesParam], - constArray([t.stringLiteral(op.name), t.identifier('variables')]) + constArray([t.stringLiteral(op.name), t.identifier('variables')]), ); prop = t.objectProperty(t.identifier(op.name), arrowFn); } else { const arrowFn = t.arrowFunctionExpression( [], - constArray([t.stringLiteral(op.name)]) + constArray([t.stringLiteral(op.name)]), ); prop = t.objectProperty(t.identifier(op.name), arrowFn); @@ -505,9 +583,9 @@ function generateCustomQueryKeysDeclaration( t.variableDeclaration('const', [ t.variableDeclarator( t.identifier('customQueryKeys'), - asConst(t.objectExpression(properties)) - ) - ]) + asConst(t.objectExpression(properties)), + ), + ]), ); } @@ -516,7 +594,7 @@ function generateCustomQueryKeysDeclaration( */ function generateUnifiedStoreDeclaration( tables: CleanTable[], - hasCustomQueries: boolean + hasCustomQueries: boolean, ): t.ExportNamedDeclaration { const properties: t.ObjectProperty[] = []; @@ -524,13 +602,13 @@ function generateUnifiedStoreDeclaration( const { typeName } = getTableNames(table); const keysName = `${lcFirst(typeName)}Keys`; properties.push( - t.objectProperty(t.identifier(lcFirst(typeName)), t.identifier(keysName)) + t.objectProperty(t.identifier(lcFirst(typeName)), t.identifier(keysName)), ); } if (hasCustomQueries) { properties.push( - t.objectProperty(t.identifier('custom'), t.identifier('customQueryKeys')) + t.objectProperty(t.identifier('custom'), t.identifier('customQueryKeys')), ); } @@ -538,9 +616,9 @@ function generateUnifiedStoreDeclaration( t.variableDeclaration('const', [ t.variableDeclarator( t.identifier('queryKeys'), - asConst(t.objectExpression(properties)) - ) - ]) + asConst(t.objectExpression(properties)), + ), + ]), ); addJSDocComment(decl, [ @@ -568,7 +646,7 @@ function generateUnifiedStoreDeclaration( * Generate the complete query-keys.ts file */ export function generateQueryKeysFile( - options: QueryKeyGeneratorOptions + options: QueryKeyGeneratorOptions, ): GeneratedQueryKeysFile { const { tables, customQueries, config } = options; const { relationships, generateScopedKeys } = config; @@ -593,7 +671,9 @@ export function generateQueryKeysFile( // Generate entity keys for (const table of tables) { - statements.push(generateEntityKeysDeclaration(table, relationships, generateScopedKeys)); + statements.push( + generateEntityKeysDeclaration(table, relationships, generateScopedKeys), + ); } // Generate custom query keys @@ -604,17 +684,21 @@ export function generateQueryKeysFile( } // Generate unified store - statements.push(generateUnifiedStoreDeclaration(tables, queryOperations.length > 0)); + statements.push( + generateUnifiedStoreDeclaration(tables, queryOperations.length > 0), + ); // Generate QueryKeyScope type const scopeTypeDecl = t.exportNamedDeclaration( t.tsTypeAliasDeclaration( t.identifier('QueryKeyScope'), null, - keyofTypeof('queryKeys') - ) + keyofTypeof('queryKeys'), + ), ); - addJSDocComment(scopeTypeDecl, ['Type representing all available query key scopes']); + addJSDocComment(scopeTypeDecl, [ + 'Type representing all available query key scopes', + ]); statements.push(scopeTypeDecl); // Generate code from AST @@ -641,7 +725,7 @@ ${description} // Add scope types section if present if (generateScopedKeys && Object.keys(relationships).length > 0) { - const hasScopes = tables.some(table => { + const hasScopes = tables.some((table) => { const { typeName } = getTableNames(table); return !!relationships[typeName.toLowerCase()]; }); @@ -656,7 +740,8 @@ ${description} // Insert section comments into the generated code const codeLines = code.split('\n'); - let inScopeTypes = generateScopedKeys && Object.keys(relationships).length > 0; + let inScopeTypes = + generateScopedKeys && Object.keys(relationships).length > 0; let addedEntitySection = false; let addedCustomSection = false; let addedUnifiedSection = false; @@ -665,7 +750,11 @@ ${description} const line = codeLines[i]; // Detect transition from scope types to entity keys - if (inScopeTypes && line.startsWith('export const') && line.includes('Keys =')) { + if ( + inScopeTypes && + line.startsWith('export const') && + line.includes('Keys =') + ) { content += `// ============================================================================ // Entity Query Keys // ============================================================================ @@ -676,7 +765,10 @@ ${description} } // Detect custom query keys section - if (!addedCustomSection && line.startsWith('export const customQueryKeys')) { + if ( + !addedCustomSection && + line.startsWith('export const customQueryKeys') + ) { content += ` // ============================================================================ // Custom Query Keys @@ -704,11 +796,14 @@ ${description} if (!addedEntitySection && !inScopeTypes) { const firstExportIndex = content.indexOf('\nexport const'); if (firstExportIndex !== -1) { - content = content.slice(0, firstExportIndex) + ` + content = + content.slice(0, firstExportIndex) + + ` // ============================================================================ // Entity Query Keys // ============================================================================ -` + content.slice(firstExportIndex); +` + + content.slice(firstExportIndex); } } diff --git a/graphql/codegen/src/core/codegen/scalars.ts b/graphql/codegen/src/core/codegen/scalars.ts index f659cb095..579eb3398 100644 --- a/graphql/codegen/src/core/codegen/scalars.ts +++ b/graphql/codegen/src/core/codegen/scalars.ts @@ -75,13 +75,23 @@ export const BASE_FILTER_TYPE_NAMES = new Set([ export function scalarToTsType( scalarName: string, - options: { unknownScalar?: 'unknown' | 'name'; overrides?: Record } = {} + options: { + unknownScalar?: 'unknown' | 'name'; + overrides?: Record; + } = {}, ): string { - return options.overrides?.[scalarName] ?? SCALAR_TS_MAP[scalarName] ?? (options.unknownScalar === 'unknown' ? 'unknown' : scalarName); + return ( + options.overrides?.[scalarName] ?? + SCALAR_TS_MAP[scalarName] ?? + (options.unknownScalar === 'unknown' ? 'unknown' : scalarName) + ); } /** Get the filter type for a scalar (handles both scalar and array types) */ -export function scalarToFilterType(scalarName: string, isArray = false): string | null { +export function scalarToFilterType( + scalarName: string, + isArray = false, +): string | null { const baseName = scalarName === 'ID' ? 'UUID' : scalarName; if (isArray) { return LIST_FILTER_SCALARS.has(baseName) ? `${baseName}ListFilter` : null; diff --git a/graphql/codegen/src/core/codegen/schema-gql-ast.ts b/graphql/codegen/src/core/codegen/schema-gql-ast.ts deleted file mode 100644 index 1d51f33de..000000000 --- a/graphql/codegen/src/core/codegen/schema-gql-ast.ts +++ /dev/null @@ -1,518 +0,0 @@ -/** - * Dynamic GraphQL AST builders for custom operations - * - * Generates GraphQL query/mutation documents from CleanOperation data - * using gql-ast library for proper AST construction. - */ -import * as t from 'gql-ast'; -import { print } from 'graphql'; -import type { - DocumentNode, - FieldNode, - ArgumentNode, - VariableDefinitionNode, - TypeNode, -} from 'graphql'; -import type { - CleanOperation, - CleanArgument, - CleanTypeRef, - CleanObjectField, - TypeRegistry, -} from '../../types/schema'; -import { getBaseTypeKind, shouldSkipField } from './type-resolver'; - -// ============================================================================ -// Configuration -// ============================================================================ - -export interface FieldSelectionConfig { - /** Max depth for nested object selections */ - maxDepth: number; - /** Skip the 'query' field in payloads */ - skipQueryField: boolean; - /** Type registry for resolving nested types */ - typeRegistry?: TypeRegistry; -} - -// ============================================================================ -// Type Node Builders (GraphQL Type AST) -// ============================================================================ - -/** - * Build a GraphQL type node from CleanTypeRef - * Handles NON_NULL, LIST, and named types - */ -function buildTypeNode(typeRef: CleanTypeRef): TypeNode { - switch (typeRef.kind) { - case 'NON_NULL': - if (typeRef.ofType) { - const innerType = buildTypeNode(typeRef.ofType); - // Can't wrap NON_NULL in NON_NULL - if (innerType.kind === 'NonNullType') { - return innerType; - } - return t.nonNullType({ type: innerType as any }); - } - return t.namedType({ type: 'String' }); - - case 'LIST': - if (typeRef.ofType) { - return t.listType({ type: buildTypeNode(typeRef.ofType) }); - } - return t.listType({ type: t.namedType({ type: 'String' }) }); - - case 'SCALAR': - case 'ENUM': - case 'OBJECT': - case 'INPUT_OBJECT': - return t.namedType({ type: typeRef.name ?? 'String' }); - - default: - return t.namedType({ type: typeRef.name ?? 'String' }); - } -} - -// ============================================================================ -// Variable Definition Builders -// ============================================================================ - -/** - * Build variable definitions from operation arguments - */ -export function buildVariableDefinitions( - args: CleanArgument[] -): VariableDefinitionNode[] { - return args.map((arg) => - t.variableDefinition({ - variable: t.variable({ name: arg.name }), - type: buildTypeNode(arg.type), - }) - ); -} - -/** - * Build argument nodes that reference variables - */ -function buildArgumentNodes(args: CleanArgument[]): ArgumentNode[] { - return args.map((arg) => - t.argument({ - name: arg.name, - value: t.variable({ name: arg.name }), - }) - ); -} - -// ============================================================================ -// Field Selection Builders -// ============================================================================ - -/** - * Check if a type should have selections (is an object type) - */ -function typeNeedsSelections(typeRef: CleanTypeRef): boolean { - const baseKind = getBaseTypeKind(typeRef); - return baseKind === 'OBJECT'; -} - -/** - * Get the resolved fields for a type reference - * Uses type registry for deep resolution - */ -function getResolvedFields( - typeRef: CleanTypeRef, - typeRegistry?: TypeRegistry -): CleanObjectField[] | undefined { - // First check if fields are directly on the typeRef - if (typeRef.fields) { - return typeRef.fields; - } - - // For wrapper types, unwrap and check - if (typeRef.ofType) { - return getResolvedFields(typeRef.ofType, typeRegistry); - } - - // Look up in type registry - if (typeRegistry && typeRef.name) { - const resolved = typeRegistry.get(typeRef.name); - if (resolved?.fields) { - return resolved.fields; - } - } - - return undefined; -} - -/** - * Build field selections for an object type - * Recursively handles nested objects up to maxDepth - */ -export function buildFieldSelections( - typeRef: CleanTypeRef, - config: FieldSelectionConfig, - currentDepth: number = 0 -): FieldNode[] { - const { maxDepth, skipQueryField, typeRegistry } = config; - - // Stop recursion at max depth - if (currentDepth >= maxDepth) { - return []; - } - - const fields = getResolvedFields(typeRef, typeRegistry); - if (!fields || fields.length === 0) { - return []; - } - - const selections: FieldNode[] = []; - - for (const field of fields) { - // Skip internal fields - if (shouldSkipField(field.name, skipQueryField)) { - continue; - } - - const fieldKind = getBaseTypeKind(field.type); - - // For scalar and enum types, just add the field - if (fieldKind === 'SCALAR' || fieldKind === 'ENUM') { - selections.push(t.field({ name: field.name })); - continue; - } - - // For object types, recurse if within depth limit - if (fieldKind === 'OBJECT' && currentDepth < maxDepth - 1) { - const nestedSelections = buildFieldSelections( - field.type, - config, - currentDepth + 1 - ); - - if (nestedSelections.length > 0) { - selections.push( - t.field({ - name: field.name, - selectionSet: t.selectionSet({ selections: nestedSelections }), - }) - ); - } - } - } - - return selections; -} - -/** - * Build selections for a return type, handling connections and payloads - */ -function buildReturnTypeSelections( - returnType: CleanTypeRef, - config: FieldSelectionConfig -): FieldNode[] { - const fields = getResolvedFields(returnType, config.typeRegistry); - - if (!fields || fields.length === 0) { - return []; - } - - // Check if this is a connection type - const hasNodes = fields.some((f) => f.name === 'nodes'); - const hasTotalCount = fields.some((f) => f.name === 'totalCount'); - - if (hasNodes && hasTotalCount) { - return buildConnectionSelections(fields, config); - } - - // Check if this is a mutation payload (has clientMutationId) - const hasClientMutationId = fields.some( - (f) => f.name === 'clientMutationId' - ); - - if (hasClientMutationId) { - return buildPayloadSelections(fields, config); - } - - // Regular object - build normal selections - return buildFieldSelections(returnType, config); -} - -/** - * Build selections for a connection type - */ -function buildConnectionSelections( - fields: CleanObjectField[], - config: FieldSelectionConfig -): FieldNode[] { - const selections: FieldNode[] = []; - - // Add totalCount - const totalCountField = fields.find((f) => f.name === 'totalCount'); - if (totalCountField) { - selections.push(t.field({ name: 'totalCount' })); - } - - // Add nodes with nested selections - const nodesField = fields.find((f) => f.name === 'nodes'); - if (nodesField) { - const nodeSelections = buildFieldSelections(nodesField.type, config); - if (nodeSelections.length > 0) { - selections.push( - t.field({ - name: 'nodes', - selectionSet: t.selectionSet({ selections: nodeSelections }), - }) - ); - } - } - - // Add pageInfo - const pageInfoField = fields.find((f) => f.name === 'pageInfo'); - if (pageInfoField) { - selections.push( - t.field({ - name: 'pageInfo', - selectionSet: t.selectionSet({ - selections: [ - t.field({ name: 'hasNextPage' }), - t.field({ name: 'hasPreviousPage' }), - t.field({ name: 'startCursor' }), - t.field({ name: 'endCursor' }), - ], - }), - }) - ); - } - - return selections; -} - -/** - * Build selections for a mutation payload type - */ -function buildPayloadSelections( - fields: CleanObjectField[], - config: FieldSelectionConfig -): FieldNode[] { - const selections: FieldNode[] = []; - - for (const field of fields) { - // Skip query field - if (shouldSkipField(field.name, config.skipQueryField)) { - continue; - } - - const fieldKind = getBaseTypeKind(field.type); - - // Add scalar fields directly - if (fieldKind === 'SCALAR' || fieldKind === 'ENUM') { - selections.push(t.field({ name: field.name })); - continue; - } - - // For object fields (like the returned entity), add with selections - if (fieldKind === 'OBJECT') { - const nestedSelections = buildFieldSelections(field.type, config); - if (nestedSelections.length > 0) { - selections.push( - t.field({ - name: field.name, - selectionSet: t.selectionSet({ selections: nestedSelections }), - }) - ); - } - } - } - - return selections; -} - -// ============================================================================ -// Custom Query Builder -// ============================================================================ - -export interface CustomQueryConfig { - operation: CleanOperation; - typeRegistry?: TypeRegistry; - maxDepth?: number; - skipQueryField?: boolean; -} - -/** - * Build a custom query AST from a CleanOperation - */ -export function buildCustomQueryAST(config: CustomQueryConfig): DocumentNode { - const { - operation, - typeRegistry, - maxDepth = 2, - skipQueryField = true, - } = config; - - const operationName = `${ucFirst(operation.name)}Query`; - - // Build variable definitions - const variableDefinitions = buildVariableDefinitions(operation.args); - - // Build arguments that reference the variables - const args = buildArgumentNodes(operation.args); - - // Build return type selections - const fieldSelectionConfig: FieldSelectionConfig = { - maxDepth, - skipQueryField, - typeRegistry, - }; - - const returnTypeNeedsSelections = typeNeedsSelections(operation.returnType); - let selections: FieldNode[] = []; - - if (returnTypeNeedsSelections) { - selections = buildReturnTypeSelections( - operation.returnType, - fieldSelectionConfig - ); - } - - // Build the query field - const queryField: FieldNode = - selections.length > 0 - ? t.field({ - name: operation.name, - args: args.length > 0 ? args : undefined, - selectionSet: t.selectionSet({ selections }), - }) - : t.field({ - name: operation.name, - args: args.length > 0 ? args : undefined, - }); - - return t.document({ - definitions: [ - t.operationDefinition({ - operation: 'query', - name: operationName, - variableDefinitions: - variableDefinitions.length > 0 ? variableDefinitions : undefined, - selectionSet: t.selectionSet({ - selections: [queryField], - }), - }), - ], - }); -} - -// ============================================================================ -// Custom Mutation Builder -// ============================================================================ - -export interface CustomMutationConfig { - operation: CleanOperation; - typeRegistry?: TypeRegistry; - maxDepth?: number; - skipQueryField?: boolean; -} - -/** - * Build a custom mutation AST from a CleanOperation - */ -export function buildCustomMutationAST( - config: CustomMutationConfig -): DocumentNode { - const { - operation, - typeRegistry, - maxDepth = 2, - skipQueryField = true, - } = config; - - const operationName = `${ucFirst(operation.name)}Mutation`; - - // Build variable definitions - const variableDefinitions = buildVariableDefinitions(operation.args); - - // Build arguments that reference the variables - const args = buildArgumentNodes(operation.args); - - // Build return type selections - const fieldSelectionConfig: FieldSelectionConfig = { - maxDepth, - skipQueryField, - typeRegistry, - }; - - const returnTypeNeedsSelections = typeNeedsSelections(operation.returnType); - let selections: FieldNode[] = []; - - if (returnTypeNeedsSelections) { - selections = buildReturnTypeSelections( - operation.returnType, - fieldSelectionConfig - ); - } - - // Build the mutation field - const mutationField: FieldNode = - selections.length > 0 - ? t.field({ - name: operation.name, - args: args.length > 0 ? args : undefined, - selectionSet: t.selectionSet({ selections }), - }) - : t.field({ - name: operation.name, - args: args.length > 0 ? args : undefined, - }); - - return t.document({ - definitions: [ - t.operationDefinition({ - operation: 'mutation', - name: operationName, - variableDefinitions: - variableDefinitions.length > 0 ? variableDefinitions : undefined, - selectionSet: t.selectionSet({ - selections: [mutationField], - }), - }), - ], - }); -} - -// ============================================================================ -// Print Utilities -// ============================================================================ - -/** - * Print a document AST to GraphQL string - */ -export function printGraphQL(ast: DocumentNode): string { - return print(ast); -} - -/** - * Build and print a custom query in one call - */ -export function buildCustomQueryString(config: CustomQueryConfig): string { - return printGraphQL(buildCustomQueryAST(config)); -} - -/** - * Build and print a custom mutation in one call - */ -export function buildCustomMutationString( - config: CustomMutationConfig -): string { - return printGraphQL(buildCustomMutationAST(config)); -} - -// ============================================================================ -// Helper Utilities -// ============================================================================ - -/** - * Uppercase first character - */ -function ucFirst(str: string): string { - return str.charAt(0).toUpperCase() + str.slice(1); -} diff --git a/graphql/codegen/src/core/codegen/schema-types-generator.ts b/graphql/codegen/src/core/codegen/schema-types-generator.ts index b4bc6a655..c2be2b36b 100644 --- a/graphql/codegen/src/core/codegen/schema-types-generator.ts +++ b/graphql/codegen/src/core/codegen/schema-types-generator.ts @@ -11,19 +11,20 @@ * * Uses Babel AST for robust code generation. */ +import * as t from '@babel/types'; + import type { - TypeRegistry, CleanArgument, ResolvedType, + TypeRegistry, } from '../../types/schema'; -import * as t from '@babel/types'; import { generateCode } from './babel-ast'; -import { getTypeBaseName } from './type-resolver'; import { - scalarToTsType, - SCALAR_NAMES, BASE_FILTER_TYPE_NAMES, + SCALAR_NAMES, + scalarToTsType, } from './scalars'; +import { getTypeBaseName } from './type-resolver'; import { getGeneratedFileHeader } from './utils'; export interface GeneratedSchemaTypesFile { @@ -79,7 +80,7 @@ function isRequired(typeRef: CleanArgument['type']): boolean { function shouldSkipType( typeName: string, - tableTypeNames: Set + tableTypeNames: Set, ): boolean { if (SKIP_TYPES.has(typeName)) return true; if (tableTypeNames.has(typeName)) return true; @@ -93,7 +94,7 @@ function shouldSkipType( function generateEnumTypes( typeRegistry: TypeRegistry, - tableTypeNames: Set + tableTypeNames: Set, ): { statements: t.Statement[]; generatedTypes: Set } { const statements: t.Statement[] = []; const generatedTypes = new Set(); @@ -104,12 +105,12 @@ function generateEnumTypes( if (!typeInfo.enumValues || typeInfo.enumValues.length === 0) continue; const unionType = t.tsUnionType( - typeInfo.enumValues.map((v) => t.tsLiteralType(t.stringLiteral(v))) + typeInfo.enumValues.map((v) => t.tsLiteralType(t.stringLiteral(v))), ); const typeAlias = t.tsTypeAliasDeclaration( t.identifier(typeName), null, - unionType + unionType, ); statements.push(t.exportNamedDeclaration(typeAlias)); generatedTypes.add(typeName); @@ -121,7 +122,7 @@ function generateEnumTypes( function generateInputObjectTypes( typeRegistry: TypeRegistry, tableTypeNames: Set, - alreadyGenerated: Set + alreadyGenerated: Set, ): { statements: t.Statement[]; generatedTypes: Set } { const statements: t.Statement[] = []; const generatedTypes = new Set(alreadyGenerated); @@ -156,7 +157,7 @@ function generateInputObjectTypes( const prop = t.tsPropertySignature( t.identifier(field.name), - t.tsTypeAnnotation(t.tsTypeReference(t.identifier(tsType))) + t.tsTypeAnnotation(t.tsTypeReference(t.identifier(tsType))), ); prop.optional = optional; properties.push(prop); @@ -179,7 +180,7 @@ function generateInputObjectTypes( t.identifier(typeName), null, null, - t.tsInterfaceBody(properties) + t.tsInterfaceBody(properties), ); statements.push(t.exportNamedDeclaration(interfaceDecl)); } @@ -190,7 +191,7 @@ function generateInputObjectTypes( function generateUnionTypes( typeRegistry: TypeRegistry, tableTypeNames: Set, - alreadyGenerated: Set + alreadyGenerated: Set, ): { statements: t.Statement[]; generatedTypes: Set } { const statements: t.Statement[] = []; const generatedTypes = new Set(alreadyGenerated); @@ -199,15 +200,16 @@ function generateUnionTypes( if (typeInfo.kind !== 'UNION') continue; if (shouldSkipType(typeName, tableTypeNames)) continue; if (generatedTypes.has(typeName)) continue; - if (!typeInfo.possibleTypes || typeInfo.possibleTypes.length === 0) continue; + if (!typeInfo.possibleTypes || typeInfo.possibleTypes.length === 0) + continue; const unionType = t.tsUnionType( - typeInfo.possibleTypes.map((pt) => t.tsTypeReference(t.identifier(pt))) + typeInfo.possibleTypes.map((pt) => t.tsTypeReference(t.identifier(pt))), ); const typeAlias = t.tsTypeAliasDeclaration( t.identifier(typeName), null, - unionType + unionType, ); statements.push(t.exportNamedDeclaration(typeAlias)); generatedTypes.add(typeName); @@ -224,7 +226,7 @@ export interface PayloadTypesResult { function collectReturnTypesFromRootTypes( typeRegistry: TypeRegistry, - tableTypeNames: Set + tableTypeNames: Set, ): Set { const returnTypes = new Set(); @@ -253,7 +255,7 @@ function collectReturnTypesFromRootTypes( function generatePayloadObjectTypes( typeRegistry: TypeRegistry, tableTypeNames: Set, - alreadyGenerated: Set + alreadyGenerated: Set, ): PayloadTypesResult { const statements: t.Statement[] = []; const generatedTypes = new Set(alreadyGenerated); @@ -261,7 +263,7 @@ function generatePayloadObjectTypes( const typesToGenerate = collectReturnTypesFromRootTypes( typeRegistry, - tableTypeNames + tableTypeNames, ); for (const typeName of Array.from(typesToGenerate)) { @@ -298,7 +300,7 @@ function generatePayloadObjectTypes( const prop = t.tsPropertySignature( t.identifier(field.name), - t.tsTypeAnnotation(t.tsTypeReference(t.identifier(finalType))) + t.tsTypeAnnotation(t.tsTypeReference(t.identifier(finalType))), ); prop.optional = isNullable; properties.push(prop); @@ -324,7 +326,7 @@ function generatePayloadObjectTypes( t.identifier(typeName), null, null, - t.tsInterfaceBody(properties) + t.tsInterfaceBody(properties), ); statements.push(t.exportNamedDeclaration(interfaceDecl)); } @@ -333,7 +335,7 @@ function generatePayloadObjectTypes( } export function generateSchemaTypesFile( - options: GenerateSchemaTypesOptions + options: GenerateSchemaTypesOptions, ): GeneratedSchemaTypesFile { const { typeRegistry, tableTypeNames } = options; @@ -346,33 +348,35 @@ export function generateSchemaTypesFile( const unionResult = generateUnionTypes( typeRegistry, tableTypeNames, - generatedTypes + generatedTypes, ); generatedTypes = new Set([...generatedTypes, ...unionResult.generatedTypes]); const inputResult = generateInputObjectTypes( typeRegistry, tableTypeNames, - generatedTypes + generatedTypes, ); generatedTypes = new Set([...generatedTypes, ...inputResult.generatedTypes]); const payloadResult = generatePayloadObjectTypes( typeRegistry, tableTypeNames, - generatedTypes + generatedTypes, ); const referencedTableTypes = Array.from( - payloadResult.referencedTableTypes + payloadResult.referencedTableTypes, ).sort(); const baseFilterImports = Array.from(BASE_FILTER_TYPE_NAMES).sort(); const allTypesImports = [...referencedTableTypes, ...baseFilterImports]; if (allTypesImports.length > 0) { const typesImport = t.importDeclaration( - allTypesImports.map((ti) => t.importSpecifier(t.identifier(ti), t.identifier(ti))), - t.stringLiteral('./types') + allTypesImports.map((ti) => + t.importSpecifier(t.identifier(ti), t.identifier(ti)), + ), + t.stringLiteral('./types'), ); typesImport.importKind = 'type'; allStatements.push(typesImport); @@ -384,7 +388,10 @@ export function generateSchemaTypesFile( allStatements.push(...payloadResult.statements); const code = generateCode(allStatements); - const content = getGeneratedFileHeader('GraphQL schema types for custom operations') + '\n\n' + code; + const content = + getGeneratedFileHeader('GraphQL schema types for custom operations') + + '\n\n' + + code; return { fileName: 'schema-types.ts', diff --git a/graphql/codegen/src/core/codegen/select-helpers.ts b/graphql/codegen/src/core/codegen/select-helpers.ts new file mode 100644 index 000000000..76d6d89ab --- /dev/null +++ b/graphql/codegen/src/core/codegen/select-helpers.ts @@ -0,0 +1,58 @@ +/** + * Shared helpers for select type resolution in custom operations + * + * Used by custom-queries.ts, custom-mutations.ts, and orm/custom-ops-generator.ts + */ +import type { CleanArgument } from '../../types/schema'; +import { SCALAR_NAMES } from './scalars'; +import { getTypeBaseName } from './type-resolver'; + +/** + * Types that don't need Select types (scalars + root query/mutation types) + */ +export const NON_SELECT_TYPES = new Set([ + ...SCALAR_NAMES, + 'Query', + 'Mutation', +]); + +/** + * Get the Select type name for a return type. + * Returns null for scalar types, Connection types, and root types. + */ +export function getSelectTypeName( + returnType: CleanArgument['type'], +): string | null { + const baseName = getTypeBaseName(returnType); + if ( + baseName && + !NON_SELECT_TYPES.has(baseName) && + !baseName.endsWith('Connection') + ) { + return `${baseName}Select`; + } + return null; +} + +/** + * Wrap a type reference in InferSelectResult, handling NON_NULL and LIST wrappers. + */ +export function wrapInferSelectResult( + typeRef: CleanArgument['type'], + payloadTypeName: string, + selectType: string = 'S', +): string { + if (typeRef.kind === 'NON_NULL' && typeRef.ofType) { + return wrapInferSelectResult( + typeRef.ofType as CleanArgument['type'], + payloadTypeName, + selectType, + ); + } + + if (typeRef.kind === 'LIST' && typeRef.ofType) { + return `${wrapInferSelectResult(typeRef.ofType as CleanArgument['type'], payloadTypeName, selectType)}[]`; + } + + return `InferSelectResult<${payloadTypeName}, ${selectType}>`; +} diff --git a/graphql/codegen/src/core/codegen/selection.ts b/graphql/codegen/src/core/codegen/selection.ts new file mode 100644 index 000000000..73a3fb5c7 --- /dev/null +++ b/graphql/codegen/src/core/codegen/selection.ts @@ -0,0 +1,42 @@ +/** + * Selection helper generator for React Query hooks + * + * Uses template-copy pattern: reads hooks-selection.ts from templates/ + * and writes it to the output directory with a generated file header. + */ +import * as fs from 'fs'; +import * as path from 'path'; + +import { getGeneratedFileHeader } from './utils'; + +function findTemplateFile(templateName: string): string { + const templatePath = path.join(__dirname, 'templates', templateName); + if (fs.existsSync(templatePath)) { + return templatePath; + } + throw new Error( + `Could not find template file: ${templateName}. Searched in: ${templatePath}`, + ); +} + +function readTemplateFile(templateName: string, description: string): string { + const templatePath = findTemplateFile(templateName); + let content = fs.readFileSync(templatePath, 'utf-8'); + const headerPattern = + /\/\*\*[\s\S]*?\* NOTE: This file is read at codegen time and written to output\.[\s\S]*?\*\/\n*/; + content = content.replace( + headerPattern, + getGeneratedFileHeader(description) + '\n', + ); + return content; +} + +/** + * Generate selection.ts content - shared selection types + runtime mappers + */ +export function generateSelectionFile(): string { + return readTemplateFile( + 'hooks-selection.ts', + 'Selection helpers for React Query hooks', + ); +} diff --git a/graphql/codegen/src/core/codegen/shared/index.ts b/graphql/codegen/src/core/codegen/shared/index.ts index ccf6819fe..730194b94 100644 --- a/graphql/codegen/src/core/codegen/shared/index.ts +++ b/graphql/codegen/src/core/codegen/shared/index.ts @@ -11,12 +11,17 @@ * schema-types.ts - Enums, input types, payload types * filters.ts - Filter types (StringFilter, IntFilter, etc.) */ -import type { CleanTable, CleanOperation, TypeRegistry } from '../../../types/schema'; -import type { GraphQLSDKConfigTarget } from '../../../types/config'; import * as t from '@babel/types'; -import { generateCode, addJSDocComment } from '../babel-ast'; -import { generateTypesFile } from '../types'; + +import type { GraphQLSDKConfigTarget } from '../../../types/config'; +import type { + CleanOperation, + CleanTable, + TypeRegistry, +} from '../../../types/schema'; +import { addJSDocComment, generateCode } from '../babel-ast'; import { generateSchemaTypesFile } from '../schema-types-generator'; +import { generateTypesFile } from '../types'; import { getTableNames } from '../utils'; /** @@ -50,7 +55,9 @@ export interface GenerateSharedResult { /** * Generate shared types that can be imported by both React Query SDK and ORM client */ -export function generateSharedTypes(options: GenerateSharedOptions): GenerateSharedResult { +export function generateSharedTypes( + options: GenerateSharedOptions, +): GenerateSharedResult { const { tables, customOperations } = options; const files: GeneratedFile[] = []; @@ -125,5 +132,5 @@ function generateSharedBarrel(hasSchemaTypes: boolean): string { return generateCode(statements); } -export { generateTypesFile } from '../types'; export { generateSchemaTypesFile } from '../schema-types-generator'; +export { generateTypesFile } from '../types'; diff --git a/graphql/codegen/src/core/codegen/templates/client.browser.ts b/graphql/codegen/src/core/codegen/templates/client.browser.ts deleted file mode 100644 index 6db2d891c..000000000 --- a/graphql/codegen/src/core/codegen/templates/client.browser.ts +++ /dev/null @@ -1,271 +0,0 @@ -/** - * GraphQL client configuration and execution (Browser-compatible) - * - * This is the RUNTIME code that gets copied to generated output. - * Uses native W3C fetch API for browser compatibility. - * - * NOTE: This file is read at codegen time and written to output. - * Any changes here will affect all generated clients. - */ - -// ============================================================================ -// Configuration -// ============================================================================ - -export interface GraphQLClientConfig { - /** GraphQL endpoint URL */ - endpoint: string; - /** Default headers to include in all requests */ - headers?: Record; - /** Dynamic headers callback called on every request */ - getHeaders?: () => Record; -} - -let globalConfig: GraphQLClientConfig | null = null; - -/** - * Configure the GraphQL client - * - * @example - * ```ts - * import { configure } from './generated'; - * - * configure({ - * endpoint: 'https://api.example.com/graphql', - * headers: { - * Authorization: 'Bearer ', - * }, - * }); - * ``` - */ -export function configure(config: GraphQLClientConfig): void { - globalConfig = config; -} - -/** - * Get the current configuration - * @throws Error if not configured - */ -export function getConfig(): GraphQLClientConfig { - if (!globalConfig) { - throw new Error( - 'GraphQL client not configured. Call configure() before making requests.' - ); - } - return globalConfig; -} - -/** - * Set a single header value - * Useful for updating Authorization after login - * - * @example - * ```ts - * setHeader('Authorization', 'Bearer '); - * ``` - */ -export function setHeader(key: string, value: string): void { - const config = getConfig(); - globalConfig = { - ...config, - headers: { ...config.headers, [key]: value }, - }; -} - -/** - * Merge multiple headers into the current configuration - * - * @example - * ```ts - * setHeaders({ Authorization: 'Bearer ', 'X-Custom': 'value' }); - * ``` - */ -export function setHeaders(headers: Record): void { - const config = getConfig(); - globalConfig = { - ...config, - headers: { ...config.headers, ...headers }, - }; -} - -// ============================================================================ -// Error handling -// ============================================================================ - -export interface GraphQLError { - message: string; - locations?: Array<{ line: number; column: number }>; - path?: Array; - extensions?: Record; -} - -export class GraphQLClientError extends Error { - constructor( - message: string, - public errors: GraphQLError[], - public response?: Response - ) { - super(message); - this.name = 'GraphQLClientError'; - } -} - -// ============================================================================ -// Execution -// ============================================================================ - -export interface ExecuteOptions { - /** Override headers for this request */ - headers?: Record; - /** AbortSignal for request cancellation */ - signal?: AbortSignal; -} - -/** - * Execute a GraphQL operation - * - * @example - * ```ts - * const result = await execute( - * carsQueryDocument, - * { first: 10 } - * ); - * ``` - */ -export async function execute< - TData = unknown, - TVariables = Record, ->( - document: string, - variables?: TVariables, - options?: ExecuteOptions -): Promise { - const config = getConfig(); - const dynamicHeaders = config.getHeaders?.() ?? {}; - - const response = await fetch(config.endpoint, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - ...config.headers, - ...dynamicHeaders, - ...options?.headers, - }, - body: JSON.stringify({ - query: document, - variables, - }), - signal: options?.signal, - }); - - const json = await response.json(); - - if (json.errors && json.errors.length > 0) { - throw new GraphQLClientError( - json.errors[0].message || 'GraphQL request failed', - json.errors, - response - ); - } - - return json.data as TData; -} - -/** - * Execute a GraphQL operation with full response (data + errors) - * Useful when you want to handle partial data with errors - */ -export async function executeWithErrors< - TData = unknown, - TVariables = Record, ->( - document: string, - variables?: TVariables, - options?: ExecuteOptions -): Promise<{ data: TData | null; errors: GraphQLError[] | null }> { - const config = getConfig(); - const dynamicHeaders = config.getHeaders?.() ?? {}; - - const response = await fetch(config.endpoint, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - ...config.headers, - ...dynamicHeaders, - ...options?.headers, - }, - body: JSON.stringify({ - query: document, - variables, - }), - signal: options?.signal, - }); - - const json = await response.json(); - - return { - data: json.data ?? null, - errors: json.errors ?? null, - }; -} - -// ============================================================================ -// QueryClient Factory -// ============================================================================ - -/** - * Default QueryClient configuration optimized for GraphQL - * - * These defaults provide a good balance between freshness and performance: - * - staleTime: 1 minute - data considered fresh, won't refetch - * - gcTime: 5 minutes - unused data kept in cache - * - refetchOnWindowFocus: false - don't refetch when tab becomes active - * - retry: 1 - retry failed requests once - */ -export const defaultQueryClientOptions = { - defaultOptions: { - queries: { - staleTime: 1000 * 60, // 1 minute - gcTime: 1000 * 60 * 5, // 5 minutes - refetchOnWindowFocus: false, - retry: 1, - }, - }, -}; - -/** - * QueryClient options type for createQueryClient - */ -export interface CreateQueryClientOptions { - defaultOptions?: { - queries?: { - staleTime?: number; - gcTime?: number; - refetchOnWindowFocus?: boolean; - retry?: number | boolean; - retryDelay?: number | ((attemptIndex: number) => number); - }; - mutations?: { - retry?: number | boolean; - retryDelay?: number | ((attemptIndex: number) => number); - }; - }; -} - -// Note: createQueryClient is available when using with @tanstack/react-query -// Import QueryClient from '@tanstack/react-query' and use these options: -// -// import { QueryClient } from '@tanstack/react-query'; -// const queryClient = new QueryClient(defaultQueryClientOptions); -// -// Or merge with your own options: -// const queryClient = new QueryClient({ -// ...defaultQueryClientOptions, -// defaultOptions: { -// ...defaultQueryClientOptions.defaultOptions, -// queries: { -// ...defaultQueryClientOptions.defaultOptions.queries, -// staleTime: 30000, // Override specific options -// }, -// }, -// }); diff --git a/graphql/codegen/src/core/codegen/templates/client.node.ts b/graphql/codegen/src/core/codegen/templates/client.node.ts deleted file mode 100644 index 156f41ceb..000000000 --- a/graphql/codegen/src/core/codegen/templates/client.node.ts +++ /dev/null @@ -1,337 +0,0 @@ -/** - * GraphQL client configuration and execution (Node.js with native http/https) - * - * This is the RUNTIME code that gets copied to generated output. - * Uses native Node.js http/https modules. - * - * NOTE: This file is read at codegen time and written to output. - * Any changes here will affect all generated clients. - */ - -import http from 'node:http'; -import https from 'node:https'; - -// ============================================================================ -// HTTP Request Helper -// ============================================================================ - -interface HttpResponse { - statusCode: number; - statusMessage: string; - data: string; -} - -/** - * Make an HTTP/HTTPS request using native Node modules - */ -function makeRequest( - url: URL, - options: http.RequestOptions, - body: string -): Promise { - return new Promise((resolve, reject) => { - const protocol = url.protocol === 'https:' ? https : http; - - const req = protocol.request(url, options, (res) => { - let data = ''; - res.setEncoding('utf8'); - res.on('data', (chunk: string) => { - data += chunk; - }); - res.on('end', () => { - resolve({ - statusCode: res.statusCode || 0, - statusMessage: res.statusMessage || '', - data, - }); - }); - }); - - req.on('error', reject); - req.write(body); - req.end(); - }); -} - -// ============================================================================ -// Configuration -// ============================================================================ - -export interface GraphQLClientConfig { - /** GraphQL endpoint URL */ - endpoint: string; - /** Default headers to include in all requests */ - headers?: Record; - /** Dynamic headers callback called on every request */ - getHeaders?: () => Record; -} - -let globalConfig: GraphQLClientConfig | null = null; - -/** - * Configure the GraphQL client - * - * @example - * ```ts - * import { configure } from './generated'; - * - * configure({ - * endpoint: 'https://api.example.com/graphql', - * headers: { - * Authorization: 'Bearer ', - * }, - * }); - * ``` - */ -export function configure(config: GraphQLClientConfig): void { - globalConfig = config; -} - -/** - * Get the current configuration - * @throws Error if not configured - */ -export function getConfig(): GraphQLClientConfig { - if (!globalConfig) { - throw new Error( - 'GraphQL client not configured. Call configure() before making requests.' - ); - } - return globalConfig; -} - -/** - * Set a single header value - * Useful for updating Authorization after login - * - * @example - * ```ts - * setHeader('Authorization', 'Bearer '); - * ``` - */ -export function setHeader(key: string, value: string): void { - const config = getConfig(); - globalConfig = { - ...config, - headers: { ...config.headers, [key]: value }, - }; -} - -/** - * Merge multiple headers into the current configuration - * - * @example - * ```ts - * setHeaders({ Authorization: 'Bearer ', 'X-Custom': 'value' }); - * ``` - */ -export function setHeaders(headers: Record): void { - const config = getConfig(); - globalConfig = { - ...config, - headers: { ...config.headers, ...headers }, - }; -} - -// ============================================================================ -// Error handling -// ============================================================================ - -export interface GraphQLError { - message: string; - locations?: Array<{ line: number; column: number }>; - path?: Array; - extensions?: Record; -} - -export class GraphQLClientError extends Error { - constructor( - message: string, - public errors: GraphQLError[], - public statusCode?: number - ) { - super(message); - this.name = 'GraphQLClientError'; - } -} - -// ============================================================================ -// Execution -// ============================================================================ - -export interface ExecuteOptions { - /** Override headers for this request */ - headers?: Record; -} - -/** - * Execute a GraphQL operation - * - * @example - * ```ts - * const result = await execute( - * carsQueryDocument, - * { first: 10 } - * ); - * ``` - */ -export async function execute< - TData = unknown, - TVariables = Record, ->( - document: string, - variables?: TVariables, - options?: ExecuteOptions -): Promise { - const config = getConfig(); - const url = new URL(config.endpoint); - const dynamicHeaders = config.getHeaders?.() ?? {}; - - const body = JSON.stringify({ - query: document, - variables, - }); - - const requestOptions: http.RequestOptions = { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - ...config.headers, - ...dynamicHeaders, - ...options?.headers, - }, - }; - - const response = await makeRequest(url, requestOptions, body); - - if (response.statusCode < 200 || response.statusCode >= 300) { - throw new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`); - } - - const json = JSON.parse(response.data) as { - data?: TData; - errors?: GraphQLError[]; - }; - - if (json.errors && json.errors.length > 0) { - throw new GraphQLClientError( - json.errors[0].message || 'GraphQL request failed', - json.errors, - response.statusCode - ); - } - - return json.data as TData; -} - -/** - * Execute a GraphQL operation with full response (data + errors) - * Useful when you want to handle partial data with errors - */ -export async function executeWithErrors< - TData = unknown, - TVariables = Record, ->( - document: string, - variables?: TVariables, - options?: ExecuteOptions -): Promise<{ data: TData | null; errors: GraphQLError[] | null }> { - const config = getConfig(); - const url = new URL(config.endpoint); - const dynamicHeaders = config.getHeaders?.() ?? {}; - - const body = JSON.stringify({ - query: document, - variables, - }); - - const requestOptions: http.RequestOptions = { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - ...config.headers, - ...dynamicHeaders, - ...options?.headers, - }, - }; - - const response = await makeRequest(url, requestOptions, body); - - if (response.statusCode < 200 || response.statusCode >= 300) { - return { - data: null, - errors: [{ message: `HTTP ${response.statusCode}: ${response.statusMessage}` }], - }; - } - - const json = JSON.parse(response.data) as { - data?: TData; - errors?: GraphQLError[]; - }; - - return { - data: json.data ?? null, - errors: json.errors ?? null, - }; -} - -// ============================================================================ -// QueryClient Factory -// ============================================================================ - -/** - * Default QueryClient configuration optimized for GraphQL - * - * These defaults provide a good balance between freshness and performance: - * - staleTime: 1 minute - data considered fresh, won't refetch - * - gcTime: 5 minutes - unused data kept in cache - * - refetchOnWindowFocus: false - don't refetch when tab becomes active - * - retry: 1 - retry failed requests once - */ -export const defaultQueryClientOptions = { - defaultOptions: { - queries: { - staleTime: 1000 * 60, // 1 minute - gcTime: 1000 * 60 * 5, // 5 minutes - refetchOnWindowFocus: false, - retry: 1, - }, - }, -}; - -/** - * QueryClient options type for createQueryClient - */ -export interface CreateQueryClientOptions { - defaultOptions?: { - queries?: { - staleTime?: number; - gcTime?: number; - refetchOnWindowFocus?: boolean; - retry?: number | boolean; - retryDelay?: number | ((attemptIndex: number) => number); - }; - mutations?: { - retry?: number | boolean; - retryDelay?: number | ((attemptIndex: number) => number); - }; - }; -} - -// Note: createQueryClient is available when using with @tanstack/react-query -// Import QueryClient from '@tanstack/react-query' and use these options: -// -// import { QueryClient } from '@tanstack/react-query'; -// const queryClient = new QueryClient(defaultQueryClientOptions); -// -// Or merge with your own options: -// const queryClient = new QueryClient({ -// ...defaultQueryClientOptions, -// defaultOptions: { -// ...defaultQueryClientOptions.defaultOptions, -// queries: { -// ...defaultQueryClientOptions.defaultOptions.queries, -// staleTime: 30000, // Override specific options -// }, -// }, -// }); diff --git a/graphql/codegen/src/core/codegen/templates/hooks-client.ts b/graphql/codegen/src/core/codegen/templates/hooks-client.ts new file mode 100644 index 000000000..dbbaa1bc5 --- /dev/null +++ b/graphql/codegen/src/core/codegen/templates/hooks-client.ts @@ -0,0 +1,49 @@ +/** + * ORM client wrapper for React Query hooks + * + * This is the RUNTIME code that gets copied to generated output. + * Provides configure/getClient singleton for React Query hooks to access the ORM. + * + * NOTE: This file is read at codegen time and written to output. + * Any changes here will affect all generated hook clients. + */ + +import { createClient } from '../orm'; +import type { OrmClientConfig } from '../orm/client'; + +export type { OrmClientConfig } from '../orm/client'; +export type { GraphQLAdapter, GraphQLError, QueryResult } from '../orm/client'; +export { GraphQLRequestError } from '../orm/client'; + +type OrmClientInstance = ReturnType; +let client: OrmClientInstance | null = null; + +/** + * Configure the ORM client for React Query hooks + * + * @example + * ```ts + * import { configure } from './generated/hooks'; + * + * configure({ + * endpoint: 'https://api.example.com/graphql', + * headers: { Authorization: 'Bearer ' }, + * }); + * ``` + */ +export function configure(config: OrmClientConfig): void { + client = createClient(config); +} + +/** + * Get the configured ORM client instance + * @throws Error if configure() has not been called + */ +export function getClient(): OrmClientInstance { + if (!client) { + throw new Error( + 'ORM client not configured. Call configure() before using hooks.', + ); + } + return client; +} diff --git a/graphql/codegen/src/core/codegen/templates/hooks-selection.ts b/graphql/codegen/src/core/codegen/templates/hooks-selection.ts new file mode 100644 index 000000000..abb9ae48b --- /dev/null +++ b/graphql/codegen/src/core/codegen/templates/hooks-selection.ts @@ -0,0 +1,58 @@ +/** + * Selection helpers for React Query hooks + * + * This is the RUNTIME code that gets copied to generated output. + * Provides selection types and runtime mappers between hook-facing + * `selection` params and ORM-facing args (`select`, `where`, `orderBy`, etc.). + * + * NOTE: This file is read at codegen time and written to output. + * Any changes here will affect all generated hook selection helpers. + */ + +export interface SelectionConfig { + fields: TFields; +} + +export interface ListSelectionConfig< + TFields, + TWhere, + TOrderBy, +> extends SelectionConfig { + where?: TWhere; + orderBy?: TOrderBy[]; + first?: number; + last?: number; + after?: string; + before?: string; + offset?: number; +} + +export function buildSelectionArgs( + selection: SelectionConfig, +): { select: TFields } { + return { select: selection.fields }; +} + +export function buildListSelectionArgs( + selection: ListSelectionConfig, +): { + select: TFields; + where?: TWhere; + orderBy?: TOrderBy[]; + first?: number; + last?: number; + after?: string; + before?: string; + offset?: number; +} { + return { + select: selection.fields, + where: selection.where, + orderBy: selection.orderBy, + first: selection.first, + last: selection.last, + after: selection.after, + before: selection.before, + offset: selection.offset, + }; +} diff --git a/graphql/codegen/src/core/codegen/templates/orm-client.ts b/graphql/codegen/src/core/codegen/templates/orm-client.ts index a71633d67..9d474a76e 100644 --- a/graphql/codegen/src/core/codegen/templates/orm-client.ts +++ b/graphql/codegen/src/core/codegen/templates/orm-client.ts @@ -29,14 +29,14 @@ export class FetchAdapter implements GraphQLAdapter { constructor( private endpoint: string, - headers?: Record + headers?: Record, ) { this.headers = headers ?? {}; } async execute( document: string, - variables?: Record + variables?: Record, ): Promise> { const response = await fetch(this.endpoint, { method: 'POST', @@ -55,7 +55,9 @@ export class FetchAdapter implements GraphQLAdapter { return { ok: false, data: null, - errors: [{ message: `HTTP ${response.status}: ${response.statusText}` }], + errors: [ + { message: `HTTP ${response.status}: ${response.statusText}` }, + ], }; } @@ -108,7 +110,7 @@ export interface OrmClientConfig { export class GraphQLRequestError extends Error { constructor( public readonly errors: GraphQLError[], - public readonly data: unknown = null + public readonly data: unknown = null, ) { const messages = errors.map((e) => e.message).join('; '); super(`GraphQL Error: ${messages}`); @@ -126,14 +128,14 @@ export class OrmClient { this.adapter = new FetchAdapter(config.endpoint, config.headers); } else { throw new Error( - 'OrmClientConfig requires either an endpoint or a custom adapter' + 'OrmClientConfig requires either an endpoint or a custom adapter', ); } } async execute( document: string, - variables?: Record + variables?: Record, ): Promise> { return this.adapter.execute(document, variables); } diff --git a/graphql/codegen/src/core/codegen/templates/query-builder.ts b/graphql/codegen/src/core/codegen/templates/query-builder.ts index 869e210e8..122fb9d55 100644 --- a/graphql/codegen/src/core/codegen/templates/query-builder.ts +++ b/graphql/codegen/src/core/codegen/templates/query-builder.ts @@ -8,15 +8,16 @@ * Any changes here will affect all generated ORM clients. */ -import * as t from 'gql-ast'; import { parseType, print } from '@0no-co/graphql.web'; +import * as t from 'gql-ast'; import type { ArgumentNode, + EnumValueNode, FieldNode, VariableDefinitionNode, - EnumValueNode, } from 'graphql'; -import { OrmClient, QueryResult, GraphQLRequestError } from './client'; + +import { GraphQLRequestError, OrmClient, QueryResult } from './client'; export interface QueryBuilderConfig { client: OrmClient; @@ -41,7 +42,7 @@ export class QueryBuilder { async execute(): Promise> { return this.config.client.execute( this.config.document, - this.config.variables + this.config.variables, ); } @@ -72,7 +73,7 @@ export class QueryBuilder { * Execute and unwrap, calling onError callback on failure */ async unwrapOrElse( - onError: (errors: import('./client').GraphQLError[]) => D + onError: (errors: import('./client').GraphQLError[]) => D, ): Promise { const result = await this.execute(); if (!result.ok) { @@ -95,13 +96,18 @@ export class QueryBuilder { // ============================================================================ export function buildSelections( - select: Record | undefined + select: Record | undefined, + connectionFieldsMap?: Record>, + entityType?: string, ): FieldNode[] { if (!select) { return []; } const fields: FieldNode[] = []; + const entityConnections = entityType + ? connectionFieldsMap?.[entityType] + : undefined; for (const [key, value] of Object.entries(select)) { if (value === false || value === undefined) { @@ -123,15 +129,24 @@ export function buildSelections( }; if (nested.select) { - const nestedSelections = buildSelections(nested.select); + const relatedEntityType = entityConnections?.[key]; + const nestedSelections = buildSelections( + nested.select, + connectionFieldsMap, + relatedEntityType, + ); const isConnection = nested.connection === true || nested.first !== undefined || - nested.filter !== undefined; + nested.filter !== undefined || + relatedEntityType !== undefined; const args = buildArgs([ buildOptionalArg('first', nested.first), nested.filter - ? t.argument({ name: 'filter', value: buildValueAst(nested.filter) }) + ? t.argument({ + name: 'filter', + value: buildValueAst(nested.filter), + }) : null, buildEnumListArg('orderBy', nested.orderBy), ]); @@ -144,7 +159,7 @@ export function buildSelections( selectionSet: t.selectionSet({ selections: buildConnectionSelections(nestedSelections), }), - }) + }), ); } else { fields.push( @@ -152,7 +167,7 @@ export function buildSelections( name: key, args, selectionSet: t.selectionSet({ selections: nestedSelections }), - }) + }), ); } } @@ -180,10 +195,15 @@ export function buildFindManyDocument( offset?: number; }, filterTypeName: string, - orderByTypeName: string + orderByTypeName: string, + connectionFieldsMap?: Record>, ): { document: string; variables: Record } { const selections = select - ? buildSelections(select as Record) + ? buildSelections( + select as Record, + connectionFieldsMap, + operationName, + ) : [t.field({ name: 'id' })]; const variableDefinitions: VariableDefinitionNode[] = []; @@ -191,10 +211,15 @@ export function buildFindManyDocument( const variables: Record = {}; addVariable( - { varName: 'where', argName: 'filter', typeName: filterTypeName, value: args.where }, + { + varName: 'where', + argName: 'filter', + typeName: filterTypeName, + value: args.where, + }, variableDefinitions, queryArgs, - variables + variables, ); addVariable( { @@ -204,37 +229,37 @@ export function buildFindManyDocument( }, variableDefinitions, queryArgs, - variables + variables, ); addVariable( { varName: 'first', typeName: 'Int', value: args.first }, variableDefinitions, queryArgs, - variables + variables, ); addVariable( { varName: 'last', typeName: 'Int', value: args.last }, variableDefinitions, queryArgs, - variables + variables, ); addVariable( { varName: 'after', typeName: 'Cursor', value: args.after }, variableDefinitions, queryArgs, - variables + variables, ); addVariable( { varName: 'before', typeName: 'Cursor', value: args.before }, variableDefinitions, queryArgs, - variables + variables, ); addVariable( { varName: 'offset', typeName: 'Int', value: args.offset }, variableDefinitions, queryArgs, - variables + variables, ); const document = t.document({ @@ -242,7 +267,9 @@ export function buildFindManyDocument( t.operationDefinition({ operation: 'query', name: operationName + 'Query', - variableDefinitions: variableDefinitions.length ? variableDefinitions : undefined, + variableDefinitions: variableDefinitions.length + ? variableDefinitions + : undefined, selectionSet: t.selectionSet({ selections: [ t.field({ @@ -266,10 +293,15 @@ export function buildFindFirstDocument( queryField: string, select: TSelect, args: { where?: TWhere }, - filterTypeName: string + filterTypeName: string, + connectionFieldsMap?: Record>, ): { document: string; variables: Record } { const selections = select - ? buildSelections(select as Record) + ? buildSelections( + select as Record, + connectionFieldsMap, + operationName, + ) : [t.field({ name: 'id' })]; const variableDefinitions: VariableDefinitionNode[] = []; @@ -281,13 +313,18 @@ export function buildFindFirstDocument( { varName: 'first', typeName: 'Int', value: 1 }, variableDefinitions, queryArgs, - variables + variables, ); addVariable( - { varName: 'where', argName: 'filter', typeName: filterTypeName, value: args.where }, + { + varName: 'where', + argName: 'filter', + typeName: filterTypeName, + value: args.where, + }, variableDefinitions, queryArgs, - variables + variables, ); const document = t.document({ @@ -325,10 +362,15 @@ export function buildCreateDocument( entityField: string, select: TSelect, data: TData, - inputTypeName: string + inputTypeName: string, + connectionFieldsMap?: Record>, ): { document: string; variables: Record } { const selections = select - ? buildSelections(select as Record) + ? buildSelections( + select as Record, + connectionFieldsMap, + operationName, + ) : [t.field({ name: 'id' })]; return { @@ -351,17 +393,26 @@ export function buildCreateDocument( }; } -export function buildUpdateDocument( +export function buildUpdateDocument< + TSelect, + TWhere extends { id: string }, + TData, +>( operationName: string, mutationField: string, entityField: string, select: TSelect, where: TWhere, data: TData, - inputTypeName: string + inputTypeName: string, + connectionFieldsMap?: Record>, ): { document: string; variables: Record } { const selections = select - ? buildSelections(select as Record) + ? buildSelections( + select as Record, + connectionFieldsMap, + operationName, + ) : [t.field({ name: 'id' })]; return { @@ -385,13 +436,122 @@ export function buildUpdateDocument( +export function buildUpdateByPkDocument( + operationName: string, + mutationField: string, + entityField: string, + select: TSelect, + id: string | number, + data: TData, + inputTypeName: string, + idFieldName: string, + connectionFieldsMap?: Record>, +): { document: string; variables: Record } { + const selections = select + ? buildSelections( + select as Record, + connectionFieldsMap, + operationName, + ) + : [t.field({ name: 'id' })]; + + return { + document: buildInputMutationDocument({ + operationName, + mutationField, + inputTypeName, + resultSelections: [ + t.field({ + name: entityField, + selectionSet: t.selectionSet({ selections }), + }), + ], + }), + variables: { + input: { + [idFieldName]: id, + patch: data, + }, + }, + }; +} + +export function buildFindOneDocument( + operationName: string, + queryField: string, + id: string | number, + select: TSelect, + idArgName: string, + idTypeName: string, + connectionFieldsMap?: Record>, +): { document: string; variables: Record } { + const selections = select + ? buildSelections( + select as Record, + connectionFieldsMap, + operationName, + ) + : [t.field({ name: 'id' })]; + + const variableDefinitions: VariableDefinitionNode[] = [ + t.variableDefinition({ + variable: t.variable({ name: idArgName }), + type: parseType(idTypeName), + }), + ]; + + const queryArgs: ArgumentNode[] = [ + t.argument({ + name: idArgName, + value: t.variable({ name: idArgName }), + }), + ]; + + const document = t.document({ + definitions: [ + t.operationDefinition({ + operation: 'query', + name: operationName + 'Query', + variableDefinitions, + selectionSet: t.selectionSet({ + selections: [ + t.field({ + name: queryField, + args: queryArgs, + selectionSet: t.selectionSet({ selections }), + }), + ], + }), + }), + ], + }); + + return { + document: print(document), + variables: { [idArgName]: id }, + }; +} + +export function buildDeleteDocument< + TWhere extends { id: string }, + TSelect = undefined, +>( operationName: string, mutationField: string, entityField: string, where: TWhere, - inputTypeName: string + inputTypeName: string, + select?: TSelect, + connectionFieldsMap?: Record>, ): { document: string; variables: Record } { + const entitySelections = select + ? buildSelections( + select as Record, + connectionFieldsMap, + operationName, + ) + : [t.field({ name: 'id' })]; + return { document: buildInputMutationDocument({ operationName, @@ -401,7 +561,7 @@ export function buildDeleteDocument( t.field({ name: entityField, selectionSet: t.selectionSet({ - selections: [t.field({ name: 'id' })], + selections: entitySelections, }), }), ], @@ -414,13 +574,53 @@ export function buildDeleteDocument( }; } +export function buildDeleteByPkDocument( + operationName: string, + mutationField: string, + entityField: string, + id: string | number, + inputTypeName: string, + idFieldName: string, + select?: TSelect, + connectionFieldsMap?: Record>, +): { document: string; variables: Record } { + const entitySelections = select + ? buildSelections( + select as Record, + connectionFieldsMap, + operationName, + ) + : [t.field({ name: 'id' })]; + + return { + document: buildInputMutationDocument({ + operationName, + mutationField, + inputTypeName, + resultSelections: [ + t.field({ + name: entityField, + selectionSet: t.selectionSet({ selections: entitySelections }), + }), + ], + }), + variables: { + input: { + [idFieldName]: id, + }, + }, + }; +} + export function buildCustomDocument( operationType: 'query' | 'mutation', operationName: string, fieldName: string, select: TSelect, args: TArgs, - variableDefinitions: Array<{ name: string; type: string }> + variableDefinitions: Array<{ name: string; type: string }>, + connectionFieldsMap?: Record>, + entityType?: string, ): { document: string; variables: Record } { let actualSelect = select; let isConnection = false; @@ -434,20 +634,24 @@ export function buildCustomDocument( } const selections = actualSelect - ? buildSelections(actualSelect as Record) + ? buildSelections( + actualSelect as Record, + connectionFieldsMap, + entityType, + ) : []; const variableDefs = variableDefinitions.map((definition) => t.variableDefinition({ variable: t.variable({ name: definition.name }), type: parseType(definition.type), - }) + }), ); const fieldArgs = variableDefinitions.map((definition) => t.argument({ name: definition.name, value: t.variable({ name: definition.name }), - }) + }), ); const fieldSelections = isConnection @@ -491,7 +695,7 @@ function buildArgs(args: Array): ArgumentNode[] { function buildOptionalArg( name: string, - value: number | string | undefined + value: number | string | undefined, ): ArgumentNode | null { if (value === undefined) { return null; @@ -505,7 +709,7 @@ function buildOptionalArg( function buildEnumListArg( name: string, - values: string[] | undefined + values: string[] | undefined, ): ArgumentNode | null { if (!values || values.length === 0) { return null; @@ -600,7 +804,7 @@ function addVariable( spec: VariableSpec, definitions: VariableDefinitionNode[], args: ArgumentNode[], - variables: Record + variables: Record, ): void { if (spec.value === undefined) return; @@ -608,19 +812,19 @@ function addVariable( t.variableDefinition({ variable: t.variable({ name: spec.varName }), type: parseType(spec.typeName), - }) + }), ); args.push( t.argument({ name: spec.argName ?? spec.varName, value: t.variable({ name: spec.varName }), - }) + }), ); variables[spec.varName] = spec.value; } function buildValueAst( - value: unknown + value: unknown, ): | ReturnType | ReturnType @@ -661,7 +865,7 @@ function buildValueAst( t.objectField({ name: key, value: buildValueAst(val), - }) + }), ), }); } diff --git a/graphql/codegen/src/core/codegen/templates/select-types.ts b/graphql/codegen/src/core/codegen/templates/select-types.ts index 4f0360a77..e430f4339 100644 --- a/graphql/codegen/src/core/codegen/templates/select-types.ts +++ b/graphql/codegen/src/core/codegen/templates/select-types.ts @@ -48,23 +48,26 @@ export interface UpdateArgs { select?: TSelect; } -export interface DeleteArgs { +export type FindOneArgs< + TSelect, + TIdName extends string = 'id', + TId = string, +> = { + select?: TSelect; +} & Record; + +export interface DeleteArgs { where: TWhere; + select?: TSelect; } /** * Recursively validates select objects, rejecting unknown keys. * - * This type ensures that users can only select fields that actually exist - * in the GraphQL schema. It returns `never` if any excess keys are found - * at any nesting level, causing a TypeScript compile error. - * - * Why this is needed: - * TypeScript's excess property checking has a quirk where it only catches - * invalid fields when they are the ONLY fields. When mixed with valid fields - * (e.g., `{ id: true, invalidField: true }`), the structural typing allows - * the excess property through. This type explicitly checks for and rejects - * such cases. + * NOTE: This type is intentionally NOT used in generated parameter positions + * (conditional types block IDE autocompletion). Parameters use `S` directly + * with `S extends XxxSelect` constraints, which provides full + * autocompletion via TypeScript's contextual typing. * * @example * // This will cause a type error because 'invalid' doesn't exist: @@ -81,15 +84,29 @@ export type DeepExact = T extends Shape ? { [K in keyof T]: K extends keyof Shape ? T[K] extends { select: infer NS } - ? Shape[K] extends { select?: infer ShapeNS } - ? { select: DeepExact> } - : T[K] + ? Extract extends { + select?: infer ShapeNS; + } + ? DeepExact< + Omit & { + select: DeepExact>; + }, + Extract + > + : never : T[K] : never; } : never : never; +/** + * Enforces exact select shape while keeping contextual typing on `S extends XxxSelect`. + * Use this as an intersection in overloads: + * `{ select: S } & StrictSelect`. + */ +export type StrictSelect = S extends DeepExact ? {} : never; + /** * Infer result type from select configuration */ diff --git a/graphql/codegen/src/core/codegen/type-resolver.ts b/graphql/codegen/src/core/codegen/type-resolver.ts index f358cff12..32e0ee01b 100644 --- a/graphql/codegen/src/core/codegen/type-resolver.ts +++ b/graphql/codegen/src/core/codegen/type-resolver.ts @@ -4,12 +4,8 @@ * Utilities for converting CleanTypeRef and other GraphQL types * into TypeScript type strings and interface definitions. */ -import type { - CleanTypeRef, - CleanArgument, - CleanObjectField, -} from '../../types/schema'; -import { scalarToTsType as resolveScalarToTs, SCALAR_NAMES } from './scalars'; +import type { CleanTypeRef } from '../../types/schema'; +import { SCALAR_NAMES, scalarToTsType as resolveScalarToTs } from './scalars'; // ============================================================================ // Type Tracker for Collecting Referenced Types @@ -114,7 +110,10 @@ export function scalarToTsType(scalarName: string): string { * @param typeRef - The GraphQL type reference * @param tracker - Optional TypeTracker to collect referenced types */ -export function typeRefToTsType(typeRef: CleanTypeRef, tracker?: TypeTracker): string { +export function typeRefToTsType( + typeRef: CleanTypeRef, + tracker?: TypeTracker, +): string { switch (typeRef.kind) { case 'NON_NULL': // Non-null wrapper - unwrap and return the inner type @@ -162,7 +161,10 @@ export function typeRefToTsType(typeRef: CleanTypeRef, tracker?: TypeTracker): s * @param typeRef - The GraphQL type reference * @param tracker - Optional TypeTracker to collect referenced types */ -export function typeRefToNullableTsType(typeRef: CleanTypeRef, tracker?: TypeTracker): string { +export function typeRefToNullableTsType( + typeRef: CleanTypeRef, + tracker?: TypeTracker, +): string { const baseType = typeRefToTsType(typeRef, tracker); // If the outer type is NON_NULL, it's required @@ -220,41 +222,16 @@ export function getBaseTypeKind(typeRef: CleanTypeRef): CleanTypeRef['kind'] { /** * Check if a field should be skipped in selections */ -export function shouldSkipField(fieldName: string, skipQueryField: boolean): boolean { +export function shouldSkipField( + fieldName: string, + skipQueryField: boolean, +): boolean { if (skipQueryField && fieldName === 'query') return true; if (fieldName === 'nodeId') return true; if (fieldName === '__typename') return true; return false; } -/** - * Filter fields to only include selectable scalar and object fields - */ -export function getSelectableFields( - fields: CleanObjectField[] | undefined, - skipQueryField: boolean, - maxDepth: number = 2, - currentDepth: number = 0 -): CleanObjectField[] { - if (!fields || currentDepth >= maxDepth) return []; - - return fields.filter((field) => { - // Skip internal fields - if (shouldSkipField(field.name, skipQueryField)) return false; - - // Get base type kind - const baseKind = getBaseTypeKind(field.type); - - // Include scalars and enums - if (baseKind === 'SCALAR' || baseKind === 'ENUM') return true; - - // Include objects up to max depth - if (baseKind === 'OBJECT' && currentDepth < maxDepth - 1) return true; - - return false; - }); -} - // ============================================================================ // Type Name Utilities // ============================================================================ @@ -272,7 +249,7 @@ export function operationNameToPascal(name: string): string { */ export function getOperationVariablesTypeName( operationName: string, - kind: 'query' | 'mutation' + kind: 'query' | 'mutation', ): string { const pascal = operationNameToPascal(operationName); return `${pascal}${kind === 'query' ? 'Query' : 'Mutation'}Variables`; @@ -284,7 +261,7 @@ export function getOperationVariablesTypeName( */ export function getOperationResultTypeName( operationName: string, - kind: 'query' | 'mutation' + kind: 'query' | 'mutation', ): string { const pascal = operationNameToPascal(operationName); return `${pascal}${kind === 'query' ? 'Query' : 'Mutation'}Result`; @@ -296,7 +273,7 @@ export function getOperationResultTypeName( */ export function getOperationHookName( operationName: string, - kind: 'query' | 'mutation' + kind: 'query' | 'mutation', ): string { const pascal = operationNameToPascal(operationName); return `use${pascal}${kind === 'query' ? 'Query' : 'Mutation'}`; @@ -308,7 +285,7 @@ export function getOperationHookName( */ export function getOperationFileName( operationName: string, - kind: 'query' | 'mutation' + kind: 'query' | 'mutation', ): string { return `${getOperationHookName(operationName, kind)}.ts`; } @@ -327,7 +304,7 @@ export function getQueryKeyName(operationName: string): string { */ export function getDocumentConstName( operationName: string, - kind: 'query' | 'mutation' + kind: 'query' | 'mutation', ): string { return `${operationName}${kind === 'query' ? 'Query' : 'Mutation'}Document`; } diff --git a/graphql/codegen/src/core/codegen/types.ts b/graphql/codegen/src/core/codegen/types.ts index 4491ed972..9f2825eef 100644 --- a/graphql/codegen/src/core/codegen/types.ts +++ b/graphql/codegen/src/core/codegen/types.ts @@ -1,10 +1,15 @@ /** * Types generator - generates types.ts with entity interfaces using Babel AST */ -import type { CleanTable } from '../../types/schema'; import * as t from '@babel/types'; + +import type { CleanTable } from '../../types/schema'; import { generateCode } from './babel-ast'; -import { getScalarFields, fieldTypeToTs, getGeneratedFileHeader } from './utils'; +import { + fieldTypeToTs, + getGeneratedFileHeader, + getScalarFields, +} from './utils'; interface InterfaceProperty { name: string; @@ -16,32 +21,100 @@ interface InterfaceProperty { // Filter Types Configuration // ============================================================================ -type FilterOps = 'equality' | 'distinct' | 'inArray' | 'comparison' | 'string' | 'json' | 'inet' | 'fulltext' | 'listArray'; +type FilterOps = + | 'equality' + | 'distinct' + | 'inArray' + | 'comparison' + | 'string' + | 'json' + | 'inet' + | 'fulltext' + | 'listArray'; /** All filter type configurations - scalar and list filters */ -const FILTER_CONFIGS: Array<{ name: string; tsType: string; operators: FilterOps[] }> = [ +const FILTER_CONFIGS: Array<{ + name: string; + tsType: string; + operators: FilterOps[]; +}> = [ // Scalar filters - { name: 'StringFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison', 'string'] }, - { name: 'IntFilter', tsType: 'number', operators: ['equality', 'distinct', 'inArray', 'comparison'] }, - { name: 'FloatFilter', tsType: 'number', operators: ['equality', 'distinct', 'inArray', 'comparison'] }, + { + name: 'StringFilter', + tsType: 'string', + operators: ['equality', 'distinct', 'inArray', 'comparison', 'string'], + }, + { + name: 'IntFilter', + tsType: 'number', + operators: ['equality', 'distinct', 'inArray', 'comparison'], + }, + { + name: 'FloatFilter', + tsType: 'number', + operators: ['equality', 'distinct', 'inArray', 'comparison'], + }, { name: 'BooleanFilter', tsType: 'boolean', operators: ['equality'] }, - { name: 'UUIDFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray'] }, - { name: 'DatetimeFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison'] }, - { name: 'DateFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison'] }, - { name: 'JSONFilter', tsType: 'Record', operators: ['equality', 'distinct', 'json'] }, - { name: 'BigIntFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison'] }, - { name: 'BigFloatFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison'] }, + { + name: 'UUIDFilter', + tsType: 'string', + operators: ['equality', 'distinct', 'inArray'], + }, + { + name: 'DatetimeFilter', + tsType: 'string', + operators: ['equality', 'distinct', 'inArray', 'comparison'], + }, + { + name: 'DateFilter', + tsType: 'string', + operators: ['equality', 'distinct', 'inArray', 'comparison'], + }, + { + name: 'JSONFilter', + tsType: 'Record', + operators: ['equality', 'distinct', 'json'], + }, + { + name: 'BigIntFilter', + tsType: 'string', + operators: ['equality', 'distinct', 'inArray', 'comparison'], + }, + { + name: 'BigFloatFilter', + tsType: 'string', + operators: ['equality', 'distinct', 'inArray', 'comparison'], + }, { name: 'BitStringFilter', tsType: 'string', operators: ['equality'] }, - { name: 'InternetAddressFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison', 'inet'] }, + { + name: 'InternetAddressFilter', + tsType: 'string', + operators: ['equality', 'distinct', 'inArray', 'comparison', 'inet'], + }, { name: 'FullTextFilter', tsType: 'string', operators: ['fulltext'] }, // List filters - { name: 'StringListFilter', tsType: 'string[]', operators: ['equality', 'distinct', 'comparison', 'listArray'] }, - { name: 'IntListFilter', tsType: 'number[]', operators: ['equality', 'distinct', 'comparison', 'listArray'] }, - { name: 'UUIDListFilter', tsType: 'string[]', operators: ['equality', 'distinct', 'comparison', 'listArray'] }, + { + name: 'StringListFilter', + tsType: 'string[]', + operators: ['equality', 'distinct', 'comparison', 'listArray'], + }, + { + name: 'IntListFilter', + tsType: 'number[]', + operators: ['equality', 'distinct', 'comparison', 'listArray'], + }, + { + name: 'UUIDListFilter', + tsType: 'string[]', + operators: ['equality', 'distinct', 'comparison', 'listArray'], + }, ]; /** Build filter properties based on operator sets */ -function buildFilterProperties(tsType: string, operators: FilterOps[]): InterfaceProperty[] { +function buildFilterProperties( + tsType: string, + operators: FilterOps[], +): InterfaceProperty[] { const props: InterfaceProperty[] = []; // Equality operators (isNull, equalTo, notEqualTo) @@ -161,7 +234,9 @@ function parseTypeAnnotation(typeStr: string): t.TSType { if (typeStr === 'unknown') return t.tsUnknownKeyword(); if (typeStr.includes(' | ')) { - const parts = typeStr.split(' | ').map((p) => parseTypeAnnotation(p.trim())); + const parts = typeStr + .split(' | ') + .map((p) => parseTypeAnnotation(p.trim())); return t.tsUnionType(parts); } @@ -176,12 +251,12 @@ function parseTypeAnnotation(typeStr: string): t.TSType { function createInterfaceDeclaration( name: string, - properties: InterfaceProperty[] + properties: InterfaceProperty[], ): t.ExportNamedDeclaration { const props = properties.map((prop) => { const propSig = t.tsPropertySignature( t.identifier(prop.name), - t.tsTypeAnnotation(parseTypeAnnotation(prop.type)) + t.tsTypeAnnotation(parseTypeAnnotation(prop.type)), ); propSig.optional = prop.optional ?? false; return propSig; @@ -191,7 +266,7 @@ function createInterfaceDeclaration( t.identifier(name), null, null, - t.tsInterfaceBody(props) + t.tsInterfaceBody(props), ); return t.exportNamedDeclaration(interfaceDecl); } @@ -201,7 +276,7 @@ function createInterfaceDeclaration( */ export function generateTypesFile( tables: CleanTable[], - options: GenerateTypesOptions = {} + options: GenerateTypesOptions = {}, ): string { const { enumsFromSchemaTypes = [] } = options; const enumSet = new Set(enumsFromSchemaTypes); @@ -226,7 +301,10 @@ export function generateTypesFile( const specifiers = Array.from(usedEnums) .sort() .map((name) => t.importSpecifier(t.identifier(name), t.identifier(name))); - const importDecl = t.importDeclaration(specifiers, t.stringLiteral('./schema-types')); + const importDecl = t.importDeclaration( + specifiers, + t.stringLiteral('./schema-types'), + ); importDecl.importKind = 'type'; statements.push(importDecl); } @@ -245,7 +323,12 @@ export function generateTypesFile( // Generate all filter types for (const { name, tsType, operators } of FILTER_CONFIGS) { - statements.push(createInterfaceDeclaration(name, buildFilterProperties(tsType, operators))); + statements.push( + createInterfaceDeclaration( + name, + buildFilterProperties(tsType, operators), + ), + ); } const header = getGeneratedFileHeader('Entity types and filter types'); diff --git a/graphql/codegen/src/core/codegen/utils.ts b/graphql/codegen/src/core/codegen/utils.ts index dc46b8703..586201c38 100644 --- a/graphql/codegen/src/core/codegen/utils.ts +++ b/graphql/codegen/src/core/codegen/utils.ts @@ -1,13 +1,14 @@ /** * Codegen utilities - naming conventions, type mapping, and helpers */ +import { pluralize } from 'inflekt'; + import type { - CleanTable, CleanField, CleanFieldType, + CleanTable, } from '../../types/schema'; -import { scalarToTsType, scalarToFilterType } from './scalars'; -import { pluralize } from 'inflekt'; +import { scalarToFilterType, scalarToTsType } from './scalars'; // ============================================================================ // String manipulation @@ -304,7 +305,7 @@ export function fieldTypeToTs(fieldType: CleanFieldType): string { */ export function getScalarFilterType( gqlType: string, - isArray = false + isArray = false, ): string | null { const cleanType = gqlType.replace(/!/g, ''); return scalarToFilterType(cleanType, isArray); diff --git a/graphql/codegen/src/core/config/index.ts b/graphql/codegen/src/core/config/index.ts index 239e5581b..a79e71987 100644 --- a/graphql/codegen/src/core/config/index.ts +++ b/graphql/codegen/src/core/config/index.ts @@ -8,10 +8,9 @@ export { loadConfigFile, type LoadConfigFileResult, } from './loader'; - export { - loadAndResolveConfig, - loadWatchConfig, type ConfigOverrideOptions, + loadAndResolveConfig, type LoadConfigResult, + loadWatchConfig, } from './resolver'; diff --git a/graphql/codegen/src/core/config/loader.ts b/graphql/codegen/src/core/config/loader.ts index 2a80524c5..87afc3b61 100644 --- a/graphql/codegen/src/core/config/loader.ts +++ b/graphql/codegen/src/core/config/loader.ts @@ -6,6 +6,7 @@ */ import * as fs from 'node:fs'; import * as path from 'node:path'; + import { createJiti } from 'jiti'; export const CONFIG_FILENAME = 'graphql-codegen.config.ts'; @@ -14,7 +15,7 @@ export const CONFIG_FILENAME = 'graphql-codegen.config.ts'; * Find the nearest config file by walking up directories */ export function findConfigFile( - startDir: string = process.cwd() + startDir: string = process.cwd(), ): string | null { let currentDir = startDir; @@ -48,7 +49,7 @@ export interface LoadConfigFileResult { * tsx or ts-node installed. */ export async function loadConfigFile( - configPath: string + configPath: string, ): Promise { const resolvedPath = path.resolve(configPath); diff --git a/graphql/codegen/src/core/config/resolver.ts b/graphql/codegen/src/core/config/resolver.ts index 56c551e3b..8f81b7110 100644 --- a/graphql/codegen/src/core/config/resolver.ts +++ b/graphql/codegen/src/core/config/resolver.ts @@ -8,7 +8,7 @@ import type { GraphQLSDKConfig, GraphQLSDKConfigTarget, } from '../../types/config'; -import { mergeConfig, getConfigOptions } from '../../types/config'; +import { getConfigOptions, mergeConfig } from '../../types/config'; import { findConfigFile, loadConfigFile } from './loader'; /** @@ -38,7 +38,7 @@ export interface LoadConfigResult { * 3. Returns fully resolved configuration ready for use */ export async function loadAndResolveConfig( - options: ConfigOverrideOptions + options: ConfigOverrideOptions, ): Promise { // Destructure CLI-only fields, rest is config overrides const { config: configPath, ...overrides } = options; @@ -77,9 +77,7 @@ export async function loadAndResolveConfig( // Check if we have a source (endpoint, schemaFile, or db) const hasSource = - mergedConfig.endpoint || - mergedConfig.schemaFile || - mergedConfig.db; + mergedConfig.endpoint || mergedConfig.schemaFile || mergedConfig.db; if (!hasSource) { return { @@ -147,14 +145,14 @@ export async function loadWatchConfig(options: { if (!mergedConfig.endpoint) { console.error( - 'x No endpoint specified. Watch mode only supports live endpoints.' + 'x No endpoint specified. Watch mode only supports live endpoints.', ); return null; } if (mergedConfig.schemaFile) { console.error( - 'x Watch mode is only supported with an endpoint, not schemaFile.' + 'x Watch mode is only supported with an endpoint, not schemaFile.', ); return null; } diff --git a/graphql/codegen/src/core/custom-ast.ts b/graphql/codegen/src/core/custom-ast.ts index 5d9a1428e..c7560a56c 100644 --- a/graphql/codegen/src/core/custom-ast.ts +++ b/graphql/codegen/src/core/custom-ast.ts @@ -182,6 +182,6 @@ function toFieldArray(strArr: string[]): FieldNode[] { export function isIntervalType(obj: unknown): boolean { if (!obj || typeof obj !== 'object') return false; return ['days', 'hours', 'minutes', 'months', 'seconds', 'years'].every( - (key) => Object.prototype.hasOwnProperty.call(obj, key) + (key) => Object.prototype.hasOwnProperty.call(obj, key), ); } diff --git a/graphql/codegen/src/core/database/index.ts b/graphql/codegen/src/core/database/index.ts index 74c41cb03..6916dce38 100644 --- a/graphql/codegen/src/core/database/index.ts +++ b/graphql/codegen/src/core/database/index.ts @@ -6,6 +6,7 @@ import * as fs from 'node:fs'; import * as path from 'node:path'; + import { buildSchemaSDL } from '@constructive-io/graphql-server'; export interface BuildSchemaFromDatabaseOptions { @@ -36,7 +37,7 @@ export interface BuildSchemaFromDatabaseResult { * @returns The path to the generated schema file and the SDL content */ export async function buildSchemaFromDatabase( - options: BuildSchemaFromDatabaseOptions + options: BuildSchemaFromDatabaseOptions, ): Promise { const { database, schemas, outDir, filename = 'schema.graphql' } = options; diff --git a/graphql/codegen/src/core/generate.ts b/graphql/codegen/src/core/generate.ts index 51e679a2d..ac09d72f0 100644 --- a/graphql/codegen/src/core/generate.ts +++ b/graphql/codegen/src/core/generate.ts @@ -4,17 +4,17 @@ * This is the primary entry point for programmatic usage. * The CLI is a thin wrapper around this function. */ -import path from 'path'; +import path from 'node:path'; -import { createSchemaSource, validateSourceOptions } from './introspect'; -import { runCodegenPipeline, validateTablesFound } from './pipeline'; +import type { GraphQLSDKConfigTarget } from '../types/config'; +import { getConfigOptions } from '../types/config'; import { generate as generateReactQueryFiles } from './codegen'; import { generateRootBarrel } from './codegen/barrel'; import { generateOrm as generateOrmFiles } from './codegen/orm'; import { generateSharedTypes } from './codegen/shared'; +import { createSchemaSource, validateSourceOptions } from './introspect'; import { writeGeneratedFiles } from './output'; -import type { GraphQLSDKConfigTarget } from '../types/config'; -import { getConfigOptions } from '../types/config'; +import { runCodegenPipeline, validateTablesFound } from './pipeline'; export interface GenerateOptions extends GraphQLSDKConfigTarget { authorization?: string; @@ -38,19 +38,25 @@ export interface GenerateResult { * This is the primary entry point for programmatic usage. * For multiple configs, call this function in a loop. */ -export async function generate(options: GenerateOptions = {}): Promise { +export async function generate( + options: GenerateOptions = {}, +): Promise { // Apply defaults to get resolved config const config = getConfigOptions(options); const outputRoot = config.output; // Determine which generators to run + // ORM is always required when React Query is enabled (hooks delegate to ORM) + // This handles minimist setting orm=false when --orm flag is absent const runReactQuery = config.reactQuery ?? false; - const runOrm = config.orm ?? false; + const runOrm = + runReactQuery || (options.orm !== undefined ? !!options.orm : false); if (!runReactQuery && !runOrm) { return { success: false, - message: 'No generators enabled. Use reactQuery: true or orm: true in your config.', + message: + 'No generators enabled. Use reactQuery: true or orm: true in your config.', output: outputRoot, }; } @@ -73,12 +79,12 @@ export async function generate(options: GenerateOptions = {}): Promise>; try { console.log(`Fetching schema from ${source.describe()}...`); pipelineResult = await runCodegenPipeline({ @@ -109,6 +115,7 @@ export async function generate(options: GenerateOptions = {}): Promise = []; // Generate shared types when both are enabled if (bothEnabled) { @@ -122,24 +129,11 @@ export async function generate(options: GenerateOptions = {}): Promise ({ + ...file, + path: path.posix.join('hooks', file.path), + })), + ); } // Generate ORM client if (runOrm) { - const ormDir = path.join(outputRoot, 'orm'); console.log('Generating ORM client...'); const { files } = generateOrmFiles({ tables, @@ -180,33 +166,41 @@ export async function generate(options: GenerateOptions = {}): Promise ({ + ...file, + path: path.posix.join('orm', file.path), + })), + ); } // Generate barrel file at output root // This re-exports from the appropriate subdirectories based on which generators are enabled + const barrelContent = generateRootBarrel({ + hasTypes: bothEnabled, + hasHooks: runReactQuery, + hasOrm: runOrm, + }); + filesToWrite.push({ path: 'index.ts', content: barrelContent }); + if (!options.dryRun) { - const barrelContent = generateRootBarrel({ - hasTypes: bothEnabled, - hasHooks: runReactQuery, - hasOrm: runOrm, + const writeResult = await writeGeneratedFiles(filesToWrite, outputRoot, [], { + pruneStaleFiles: true, }); - await writeGeneratedFiles([{ path: 'index.ts', content: barrelContent }], outputRoot, []); + if (!writeResult.success) { + return { + success: false, + message: `Failed to write generated files: ${writeResult.errors?.join(', ')}`, + output: outputRoot, + errors: writeResult.errors, + }; + } + allFilesWritten.push(...(writeResult.filesWritten ?? [])); } - const generators = [runReactQuery && 'React Query', runOrm && 'ORM'].filter(Boolean).join(' and '); + const generators = [runReactQuery && 'React Query', runOrm && 'ORM'] + .filter(Boolean) + .join(' and '); return { success: true, diff --git a/graphql/codegen/src/core/index.ts b/graphql/codegen/src/core/index.ts index 5dbf3eb23..3cae1c15c 100644 --- a/graphql/codegen/src/core/index.ts +++ b/graphql/codegen/src/core/index.ts @@ -6,8 +6,8 @@ */ // Main generate function (orchestrates the entire pipeline) -export { generate } from './generate'; export type { GenerateOptions, GenerateResult } from './generate'; +export { generate } from './generate'; // Types export * from './types'; @@ -17,10 +17,10 @@ export * from './ast'; export * from './custom-ast'; // Query builder -export { QueryBuilder, MetaObject } from './query-builder'; +export { MetaObject, QueryBuilder } from './query-builder'; // Meta object utilities -export { validateMetaObject, convertFromMetaSchema } from './meta-object'; +export { convertFromMetaSchema, validateMetaObject } from './meta-object'; // Configuration loading and resolution export * from './config'; diff --git a/graphql/codegen/src/core/introspect/fetch-schema.ts b/graphql/codegen/src/core/introspect/fetch-schema.ts index 81cd7b5bb..269fd5468 100644 --- a/graphql/codegen/src/core/introspect/fetch-schema.ts +++ b/graphql/codegen/src/core/introspect/fetch-schema.ts @@ -4,8 +4,9 @@ */ import http from 'node:http'; import https from 'node:https'; -import { SCHEMA_INTROSPECTION_QUERY } from './schema-query'; + import type { IntrospectionQueryResponse } from '../../types/introspection'; +import { SCHEMA_INTROSPECTION_QUERY } from './schema-query'; interface HttpResponse { statusCode: number; @@ -20,7 +21,7 @@ function makeRequest( url: URL, options: http.RequestOptions, body: string, - timeout: number + timeout: number, ): Promise { return new Promise((resolve, reject) => { const protocol = url.protocol === 'https:' ? https : http; @@ -74,7 +75,7 @@ export interface FetchSchemaResult { * Fetch the full schema introspection from a GraphQL endpoint */ export async function fetchSchema( - options: FetchSchemaOptions + options: FetchSchemaOptions, ): Promise { const { endpoint, authorization, headers = {}, timeout = 30000 } = options; diff --git a/graphql/codegen/src/core/introspect/index.ts b/graphql/codegen/src/core/introspect/index.ts index baaf7ebc2..dae6b7a4e 100644 --- a/graphql/codegen/src/core/introspect/index.ts +++ b/graphql/codegen/src/core/introspect/index.ts @@ -3,29 +3,29 @@ */ // Table inference from introspection -export { inferTablesFromIntrospection } from './infer-tables'; export type { InferTablesOptions } from './infer-tables'; +export { inferTablesFromIntrospection } from './infer-tables'; // Pluralization utilities (from inflekt) -export { singularize, pluralize } from 'inflekt'; +export { pluralize, singularize } from 'inflekt'; // Schema sources +export type { + CreateSchemaSourceOptions, + SchemaSource, + SchemaSourceResult, +} from './source'; export { createSchemaSource, - validateSourceOptions, EndpointSchemaSource, FileSchemaSource, SchemaSourceError, -} from './source'; -export type { - SchemaSource, - SchemaSourceResult, - CreateSchemaSourceOptions, + validateSourceOptions, } from './source'; // Schema fetching (still used by watch mode) -export { fetchSchema } from './fetch-schema'; export type { FetchSchemaOptions, FetchSchemaResult } from './fetch-schema'; +export { fetchSchema } from './fetch-schema'; // Transform utilities (only filterTables, getTableNames, findTable are still useful) -export { getTableNames, findTable, filterTables } from './transform'; +export { filterTables, findTable, getTableNames } from './transform'; diff --git a/graphql/codegen/src/core/introspect/infer-tables.ts b/graphql/codegen/src/core/introspect/infer-tables.ts index 9f5ab631a..90f34ee56 100644 --- a/graphql/codegen/src/core/introspect/infer-tables.ts +++ b/graphql/codegen/src/core/introspect/infer-tables.ts @@ -12,27 +12,28 @@ * - Query operations: {pluralName} (list), {singularName} (single) * - Mutation operations: create{Name}, update{Name}, delete{Name} */ +import { lcFirst, pluralize, singularize, ucFirst } from 'inflekt'; + import type { + IntrospectionField, IntrospectionQueryResponse, IntrospectionType, - IntrospectionField, IntrospectionTypeRef, } from '../../types/introspection'; -import { unwrapType, getBaseTypeName, isList } from '../../types/introspection'; +import { getBaseTypeName, isList, unwrapType } from '../../types/introspection'; import type { - CleanTable, + CleanBelongsToRelation, CleanField, CleanFieldType, - CleanRelations, - CleanBelongsToRelation, CleanHasManyRelation, CleanManyToManyRelation, + CleanRelations, + CleanTable, + ConstraintInfo, + TableConstraints, TableInflection, TableQueryNames, - TableConstraints, - ConstraintInfo, } from '../../types/schema'; -import { singularize, pluralize, lcFirst, ucFirst } from 'inflekt'; // ============================================================================ // Pattern Matching Constants @@ -118,7 +119,7 @@ export interface InferTablesOptions { */ export function inferTablesFromIntrospection( introspection: IntrospectionQueryResponse, - options: InferTablesOptions = {} + options: InferTablesOptions = {}, ): CleanTable[] { const { __schema: schema } = introspection; const { types, queryType, mutationType } = schema; @@ -146,7 +147,7 @@ export function inferTablesFromIntrospection( entityType, typeMap, queryFields, - mutationFields + mutationFields, ); // Only include tables that have at least one real operation @@ -210,7 +211,7 @@ function buildCleanTable( entityType: IntrospectionType, typeMap: Map, queryFields: IntrospectionField[], - mutationFields: IntrospectionField[] + mutationFields: IntrospectionField[], ): BuildCleanTableResult { // Extract scalar fields from entity type const fields = extractEntityFields(entityType, typeMap); @@ -270,7 +271,7 @@ function buildCleanTable( */ function extractEntityFields( entityType: IntrospectionType, - typeMap: Map + typeMap: Map, ): CleanField[] { const fields: CleanField[] = []; @@ -307,7 +308,7 @@ function extractEntityFields( */ function isEntityType( typeName: string, - typeMap: Map + typeMap: Map, ): boolean { const connectionName = `${pluralize(typeName)}Connection`; return typeMap.has(connectionName); @@ -317,7 +318,7 @@ function isEntityType( * Convert IntrospectionTypeRef to CleanFieldType */ function convertToCleanFieldType( - typeRef: IntrospectionTypeRef + typeRef: IntrospectionTypeRef, ): CleanFieldType { const baseType = unwrapType(typeRef); const isArray = isList(typeRef); @@ -339,7 +340,7 @@ function convertToCleanFieldType( */ function inferRelations( entityType: IntrospectionType, - typeMap: Map + typeMap: Map, ): CleanRelations { const belongsTo: CleanBelongsToRelation[] = []; const hasMany: CleanHasManyRelation[] = []; @@ -388,7 +389,7 @@ function inferRelations( function inferHasManyOrManyToMany( field: IntrospectionField, connectionTypeName: string, - typeMap: Map + typeMap: Map, ): | { type: 'hasMany'; relation: CleanHasManyRelation } | { type: 'manyToMany'; relation: CleanManyToManyRelation } { @@ -415,7 +416,7 @@ function inferHasManyOrManyToMany( // e.g., "productsByProductCategoryProductIdAndCategoryId" → "ProductCategory" // The junction table name ends where the first field key begins (identified by capital letter after lowercase) const junctionMatch = field.name.match( - /By([A-Z][a-z]+(?:[A-Z][a-z]+)*?)(?:[A-Z][a-z]+Id)/ + /By([A-Z][a-z]+(?:[A-Z][a-z]+)*?)(?:[A-Z][a-z]+Id)/, ); const junctionTable = junctionMatch ? junctionMatch[1] : 'Unknown'; @@ -461,7 +462,7 @@ interface QueryOperations { function matchQueryOperations( entityName: string, queryFields: IntrospectionField[], - typeMap: Map + typeMap: Map, ): QueryOperations { const pluralName = pluralize(entityName); const connectionTypeName = `${pluralName}Connection`; @@ -487,7 +488,7 @@ function matchQueryOperations( (arg) => arg.name === 'id' || arg.name === 'nodeId' || - arg.name.toLowerCase().endsWith('id') + arg.name.toLowerCase().endsWith('id'), ); if (hasIdArg) { @@ -518,7 +519,7 @@ interface MutationOperations { */ function matchMutationOperations( entityName: string, - mutationFields: IntrospectionField[] + mutationFields: IntrospectionField[], ): MutationOperations { let create: string | null = null; let update: string | null = null; @@ -572,7 +573,7 @@ function matchMutationOperations( */ function inferConstraints( entityName: string, - typeMap: Map + typeMap: Map, ): TableConstraints { const primaryKey: ConstraintInfo[] = []; @@ -587,7 +588,7 @@ function inferConstraints( const inputToCheck = updateInput || deleteInput; if (inputToCheck?.inputFields) { const idField = inputToCheck.inputFields.find( - (f) => f.name === 'id' || f.name === 'nodeId' + (f) => f.name === 'id' || f.name === 'nodeId', ); if (idField) { @@ -608,7 +609,7 @@ function inferConstraints( const entityType = typeMap.get(entityName); if (entityType?.fields) { const idField = entityType.fields.find( - (f) => f.name === 'id' || f.name === 'nodeId' + (f) => f.name === 'id' || f.name === 'nodeId', ); if (idField) { @@ -641,7 +642,7 @@ function inferConstraints( */ function buildInflection( entityName: string, - typeMap: Map + typeMap: Map, ): TableInflection { const pluralName = pluralize(entityName); const singularFieldName = lcFirst(entityName); @@ -697,7 +698,7 @@ function buildInflection( function findOrderByType( entityName: string, pluralName: string, - typeMap: Map + typeMap: Map, ): string | null { // Try the standard pattern first: {PluralName}OrderBy const standardName = `${pluralName}OrderBy`; @@ -747,7 +748,7 @@ function findOrderByType( * Build a map of type name → IntrospectionType for efficient lookup */ function buildTypeMap( - types: IntrospectionType[] + types: IntrospectionType[], ): Map { const map = new Map(); for (const type of types) { @@ -760,7 +761,7 @@ function buildTypeMap( * Get fields from a type, returning empty array if null */ function getTypeFields( - type: IntrospectionType | undefined + type: IntrospectionType | undefined, ): IntrospectionField[] { return type?.fields ?? []; } diff --git a/graphql/codegen/src/core/introspect/schema-query.ts b/graphql/codegen/src/core/introspect/schema-query.ts index 6cdf5dbfa..d1ebdcf4c 100644 --- a/graphql/codegen/src/core/introspect/schema-query.ts +++ b/graphql/codegen/src/core/introspect/schema-query.ts @@ -1,6 +1,6 @@ /** * GraphQL Schema Introspection Query - * + * * Full introspection query that captures all queries, mutations, and types * from a GraphQL endpoint via the standard __schema query. */ @@ -9,12 +9,12 @@ import type { IntrospectionQueryResponse } from '../../types/introspection'; /** * Full schema introspection query - * + * * Captures: * - All Query fields with args and return types - * - All Mutation fields with args and return types + * - All Mutation fields with args and return types * - All types (OBJECT, INPUT_OBJECT, ENUM, SCALAR) for resolution - * + * * Uses a recursive TypeRef fragment to handle deeply nested type wrappers * (e.g., [String!]! = NON_NULL(LIST(NON_NULL(SCALAR)))) */ diff --git a/graphql/codegen/src/core/introspect/source/api-schemas.ts b/graphql/codegen/src/core/introspect/source/api-schemas.ts index 4ff79229f..d4a17b62b 100644 --- a/graphql/codegen/src/core/introspect/source/api-schemas.ts +++ b/graphql/codegen/src/core/introspect/source/api-schemas.ts @@ -27,7 +27,7 @@ export interface ServicesSchemaValidation { * @returns Validation result */ export async function validateServicesSchemas( - pool: Pool + pool: Pool, ): Promise { try { // Check for services_public.apis table @@ -39,7 +39,8 @@ export async function validateServicesSchemas( if (apisCheck.rows.length === 0) { return { valid: false, - error: 'services_public.apis table not found. The database must have the services schema deployed.', + error: + 'services_public.apis table not found. The database must have the services schema deployed.', }; } @@ -52,7 +53,8 @@ export async function validateServicesSchemas( if (apiSchemasCheck.rows.length === 0) { return { valid: false, - error: 'services_public.api_schemas table not found. The database must have the services schema deployed.', + error: + 'services_public.api_schemas table not found. The database must have the services schema deployed.', }; } @@ -65,7 +67,8 @@ export async function validateServicesSchemas( if (metaschemaCheck.rows.length === 0) { return { valid: false, - error: 'metaschema_public.schema table not found. The database must have the metaschema deployed.', + error: + 'metaschema_public.schema table not found. The database must have the metaschema deployed.', }; } @@ -91,7 +94,7 @@ export async function validateServicesSchemas( */ export async function resolveApiSchemas( pool: Pool, - apiNames: string[] + apiNames: string[], ): Promise { // First validate that the required schemas exist const validation = await validateServicesSchemas(pool); @@ -109,13 +112,13 @@ export async function resolveApiSchemas( WHERE api.name = ANY($1) ORDER BY ms.schema_name `, - [apiNames] + [apiNames], ); if (result.rows.length === 0) { throw new Error( `No schemas found for API names: ${apiNames.join(', ')}. ` + - 'Ensure the APIs exist and have schemas assigned in services_public.api_schemas.' + 'Ensure the APIs exist and have schemas assigned in services_public.api_schemas.', ); } @@ -130,8 +133,9 @@ export async function resolveApiSchemas( */ export function createDatabasePool(database: string): Pool { // Check if it's a connection string or just a database name - const isConnectionString = database.startsWith('postgres://') || database.startsWith('postgresql://'); - + const isConnectionString = + database.startsWith('postgres://') || database.startsWith('postgresql://'); + if (isConnectionString) { // Parse connection string and extract database name // Format: postgres://user:password@host:port/database @@ -145,7 +149,7 @@ export function createDatabasePool(database: string): Pool { database: dbName, }); } - + // Use environment variables for connection, just override database name const config = getPgEnvOptions({ database }); return getPgPool(config); diff --git a/graphql/codegen/src/core/introspect/source/database.ts b/graphql/codegen/src/core/introspect/source/database.ts index 4b77ea12e..5071fbe0b 100644 --- a/graphql/codegen/src/core/introspect/source/database.ts +++ b/graphql/codegen/src/core/introspect/source/database.ts @@ -5,11 +5,16 @@ * introspection and converts it to introspection format. */ import { buildSchema, introspectionFromSchema } from 'graphql'; -import type { SchemaSource, SchemaSourceResult } from './types'; -import { SchemaSourceError } from './types'; + import type { IntrospectionQueryResponse } from '../../../types/introspection'; import { buildSchemaSDLFromDatabase } from '../../database'; -import { createDatabasePool, resolveApiSchemas, validateServicesSchemas } from './api-schemas'; +import { + createDatabasePool, + resolveApiSchemas, + validateServicesSchemas, +} from './api-schemas'; +import type { SchemaSource, SchemaSourceResult } from './types'; +import { SchemaSourceError } from './types'; export interface DatabaseSchemaSourceOptions { /** @@ -65,7 +70,7 @@ export class DatabaseSchemaSource implements SchemaSource { throw new SchemaSourceError( `Failed to resolve API schemas: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), - err instanceof Error ? err : undefined + err instanceof Error ? err : undefined, ); } } else { @@ -83,7 +88,7 @@ export class DatabaseSchemaSource implements SchemaSource { throw new SchemaSourceError( `Failed to introspect database: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), - err instanceof Error ? err : undefined + err instanceof Error ? err : undefined, ); } @@ -91,7 +96,7 @@ export class DatabaseSchemaSource implements SchemaSource { if (!sdl.trim()) { throw new SchemaSourceError( 'Database introspection returned empty schema', - this.describe() + this.describe(), ); } @@ -103,7 +108,7 @@ export class DatabaseSchemaSource implements SchemaSource { throw new SchemaSourceError( `Invalid GraphQL SDL from database: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), - err instanceof Error ? err : undefined + err instanceof Error ? err : undefined, ); } @@ -115,13 +120,13 @@ export class DatabaseSchemaSource implements SchemaSource { throw new SchemaSourceError( `Failed to generate introspection: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), - err instanceof Error ? err : undefined + err instanceof Error ? err : undefined, ); } // Convert graphql-js introspection result to our mutable type const introspection: IntrospectionQueryResponse = JSON.parse( - JSON.stringify(introspectionResult) + JSON.stringify(introspectionResult), ) as IntrospectionQueryResponse; return { introspection }; diff --git a/graphql/codegen/src/core/introspect/source/endpoint.ts b/graphql/codegen/src/core/introspect/source/endpoint.ts index a5c50ff84..bc952290e 100644 --- a/graphql/codegen/src/core/introspect/source/endpoint.ts +++ b/graphql/codegen/src/core/introspect/source/endpoint.ts @@ -4,9 +4,9 @@ * Fetches GraphQL schema via introspection from a live endpoint. * Wraps the existing fetchSchema() function with the SchemaSource interface. */ +import { fetchSchema } from '../fetch-schema'; import type { SchemaSource, SchemaSourceResult } from './types'; import { SchemaSourceError } from './types'; -import { fetchSchema } from '../fetch-schema'; export interface EndpointSchemaSourceOptions { /** @@ -51,14 +51,14 @@ export class EndpointSchemaSource implements SchemaSource { if (!result.success) { throw new SchemaSourceError( result.error ?? 'Unknown error fetching schema', - this.describe() + this.describe(), ); } if (!result.data) { throw new SchemaSourceError( 'No introspection data returned', - this.describe() + this.describe(), ); } diff --git a/graphql/codegen/src/core/introspect/source/file.ts b/graphql/codegen/src/core/introspect/source/file.ts index 6ab828aac..0451be703 100644 --- a/graphql/codegen/src/core/introspect/source/file.ts +++ b/graphql/codegen/src/core/introspect/source/file.ts @@ -6,10 +6,12 @@ */ import * as fs from 'node:fs'; import * as path from 'node:path'; + import { buildSchema, introspectionFromSchema } from 'graphql'; + +import type { IntrospectionQueryResponse } from '../../../types/introspection'; import type { SchemaSource, SchemaSourceResult } from './types'; import { SchemaSourceError } from './types'; -import type { IntrospectionQueryResponse } from '../../../types/introspection'; export interface FileSchemaSourceOptions { /** @@ -41,7 +43,7 @@ export class FileSchemaSource implements SchemaSource { if (!fs.existsSync(absolutePath)) { throw new SchemaSourceError( `Schema file not found: ${absolutePath}`, - this.describe() + this.describe(), ); } @@ -53,7 +55,7 @@ export class FileSchemaSource implements SchemaSource { throw new SchemaSourceError( `Failed to read schema file: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), - err instanceof Error ? err : undefined + err instanceof Error ? err : undefined, ); } @@ -70,7 +72,7 @@ export class FileSchemaSource implements SchemaSource { throw new SchemaSourceError( `Invalid GraphQL SDL: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), - err instanceof Error ? err : undefined + err instanceof Error ? err : undefined, ); } @@ -82,14 +84,14 @@ export class FileSchemaSource implements SchemaSource { throw new SchemaSourceError( `Failed to generate introspection: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), - err instanceof Error ? err : undefined + err instanceof Error ? err : undefined, ); } // Convert graphql-js introspection result to our mutable type // The graphql-js types are readonly, but our types are mutable const introspection: IntrospectionQueryResponse = JSON.parse( - JSON.stringify(introspectionResult) + JSON.stringify(introspectionResult), ) as IntrospectionQueryResponse; return { introspection }; diff --git a/graphql/codegen/src/core/introspect/source/index.ts b/graphql/codegen/src/core/introspect/source/index.ts index 9642201c0..8587d0bf1 100644 --- a/graphql/codegen/src/core/introspect/source/index.ts +++ b/graphql/codegen/src/core/introspect/source/index.ts @@ -7,23 +7,19 @@ * - PostgreSQL databases (via PostGraphile introspection) * - PGPM modules (via ephemeral database deployment) */ -export * from './types'; +export * from './api-schemas'; +export * from './database'; export * from './endpoint'; export * from './file'; -export * from './database'; export * from './pgpm-module'; -export * from './api-schemas'; +export * from './types'; -import type { SchemaSource } from './types'; -import type { DbConfig, PgpmConfig } from '../../../types/config'; +import type { DbConfig } from '../../../types/config'; +import { DatabaseSchemaSource } from './database'; import { EndpointSchemaSource } from './endpoint'; import { FileSchemaSource } from './file'; -import { DatabaseSchemaSource } from './database'; -import { - PgpmModuleSchemaSource, - isPgpmModulePathOptions, - isPgpmWorkspaceOptions, -} from './pgpm-module'; +import { PgpmModuleSchemaSource } from './pgpm-module'; +import type { SchemaSource } from './types'; /** * Options for endpoint-based schema source @@ -107,15 +103,23 @@ export interface CreateSchemaSourceOptions { /** * Detect which source mode is being used based on options */ -export type SourceMode = 'endpoint' | 'schemaFile' | 'database' | 'pgpm-module' | 'pgpm-workspace'; +export type SourceMode = + | 'endpoint' + | 'schemaFile' + | 'database' + | 'pgpm-module' + | 'pgpm-workspace'; -export function detectSourceMode(options: CreateSchemaSourceOptions): SourceMode | null { +export function detectSourceMode( + options: CreateSchemaSourceOptions, +): SourceMode | null { if (options.endpoint) return 'endpoint'; if (options.schemaFile) return 'schemaFile'; if (options.db) { // Check for PGPM modes first if (options.db.pgpm?.modulePath) return 'pgpm-module'; - if (options.db.pgpm?.workspacePath && options.db.pgpm?.moduleName) return 'pgpm-workspace'; + if (options.db.pgpm?.workspacePath && options.db.pgpm?.moduleName) + return 'pgpm-workspace'; // Default to database mode if db is specified without pgpm return 'database'; } @@ -137,7 +141,7 @@ export function detectSourceMode(options: CreateSchemaSourceOptions): SourceMode * @throws Error if no valid source is provided */ export function createSchemaSource( - options: CreateSchemaSourceOptions + options: CreateSchemaSourceOptions, ): SchemaSource { const mode = detectSourceMode(options); @@ -183,7 +187,7 @@ export function createSchemaSource( default: throw new Error( - 'No source specified. Use one of: endpoint, schemaFile, or db (with optional pgpm for module deployment).' + 'No source specified. Use one of: endpoint, schemaFile, or db (with optional pgpm for module deployment).', ); } } @@ -196,17 +200,14 @@ export function validateSourceOptions(options: CreateSchemaSourceOptions): { error?: string; } { // Count primary sources - const sources = [ - options.endpoint, - options.schemaFile, - options.db, - ].filter(Boolean); + const sources = [options.endpoint, options.schemaFile, options.db].filter( + Boolean, + ); if (sources.length === 0) { return { valid: false, - error: - 'No source specified. Use one of: endpoint, schemaFile, or db.', + error: 'No source specified. Use one of: endpoint, schemaFile, or db.', }; } @@ -224,14 +225,16 @@ export function validateSourceOptions(options: CreateSchemaSourceOptions): { if (pgpm.workspacePath && !pgpm.moduleName) { return { valid: false, - error: 'db.pgpm.workspacePath requires db.pgpm.moduleName to be specified.', + error: + 'db.pgpm.workspacePath requires db.pgpm.moduleName to be specified.', }; } if (pgpm.moduleName && !pgpm.workspacePath) { return { valid: false, - error: 'db.pgpm.moduleName requires db.pgpm.workspacePath to be specified.', + error: + 'db.pgpm.moduleName requires db.pgpm.workspacePath to be specified.', }; } @@ -239,7 +242,8 @@ export function validateSourceOptions(options: CreateSchemaSourceOptions): { if (!pgpm.modulePath && !(pgpm.workspacePath && pgpm.moduleName)) { return { valid: false, - error: 'db.pgpm requires either modulePath or both workspacePath and moduleName.', + error: + 'db.pgpm requires either modulePath or both workspacePath and moduleName.', }; } } @@ -252,14 +256,16 @@ export function validateSourceOptions(options: CreateSchemaSourceOptions): { if (hasSchemas && hasApiNames) { return { valid: false, - error: 'Cannot specify both db.schemas and db.apiNames. Use one or the other.', + error: + 'Cannot specify both db.schemas and db.apiNames. Use one or the other.', }; } if (!hasSchemas && !hasApiNames) { return { valid: false, - error: 'Must specify either db.schemas or db.apiNames for database mode.', + error: + 'Must specify either db.schemas or db.apiNames for database mode.', }; } } diff --git a/graphql/codegen/src/core/introspect/source/pgpm-module.ts b/graphql/codegen/src/core/introspect/source/pgpm-module.ts index a246d769f..2a02fa70b 100644 --- a/graphql/codegen/src/core/introspect/source/pgpm-module.ts +++ b/graphql/codegen/src/core/introspect/source/pgpm-module.ts @@ -7,17 +7,17 @@ * 3. Introspecting the database with PostGraphile * 4. Cleaning up the ephemeral database (unless keepDb is true) */ -import { buildSchema, introspectionFromSchema } from 'graphql'; import { PgpmPackage } from '@pgpmjs/core'; +import { buildSchema, introspectionFromSchema } from 'graphql'; +import { getPgPool } from 'pg-cache'; import { createEphemeralDb, type EphemeralDbResult } from 'pgsql-client'; import { deployPgpm } from 'pgsql-seed'; -import { getPgPool } from 'pg-cache'; -import type { SchemaSource, SchemaSourceResult } from './types'; -import { SchemaSourceError } from './types'; import type { IntrospectionQueryResponse } from '../../../types/introspection'; import { buildSchemaSDLFromDatabase } from '../../database'; import { resolveApiSchemas, validateServicesSchemas } from './api-schemas'; +import type { SchemaSource, SchemaSourceResult } from './types'; +import { SchemaSourceError } from './types'; /** * Options for PGPM module schema source using direct module path @@ -84,13 +84,15 @@ export interface PgpmWorkspaceOptions { keepDb?: boolean; } -export type PgpmModuleSchemaSourceOptions = PgpmModulePathOptions | PgpmWorkspaceOptions; +export type PgpmModuleSchemaSourceOptions = + | PgpmModulePathOptions + | PgpmWorkspaceOptions; /** * Type guard to check if options use direct module path */ export function isPgpmModulePathOptions( - options: PgpmModuleSchemaSourceOptions + options: PgpmModuleSchemaSourceOptions, ): options is PgpmModulePathOptions { return 'pgpmModulePath' in options; } @@ -99,7 +101,7 @@ export function isPgpmModulePathOptions( * Type guard to check if options use workspace + module name */ export function isPgpmWorkspaceOptions( - options: PgpmModuleSchemaSourceOptions + options: PgpmModuleSchemaSourceOptions, ): options is PgpmWorkspaceOptions { return 'pgpmWorkspacePath' in options && 'pgpmModuleName' in options; } @@ -130,7 +132,7 @@ export class PgpmModuleSchemaSource implements SchemaSource { throw new SchemaSourceError( `Failed to resolve module path: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), - err instanceof Error ? err : undefined + err instanceof Error ? err : undefined, ); } @@ -139,7 +141,7 @@ export class PgpmModuleSchemaSource implements SchemaSource { if (!pkg.isInModule()) { throw new SchemaSourceError( `Not a valid PGPM module: ${modulePath}. Directory must contain pgpm.plan and .control files.`, - this.describe() + this.describe(), ); } @@ -153,7 +155,7 @@ export class PgpmModuleSchemaSource implements SchemaSource { throw new SchemaSourceError( `Failed to create ephemeral database: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), - err instanceof Error ? err : undefined + err instanceof Error ? err : undefined, ); } @@ -167,7 +169,7 @@ export class PgpmModuleSchemaSource implements SchemaSource { throw new SchemaSourceError( `Failed to deploy PGPM module: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), - err instanceof Error ? err : undefined + err instanceof Error ? err : undefined, ); } @@ -187,7 +189,7 @@ export class PgpmModuleSchemaSource implements SchemaSource { throw new SchemaSourceError( `Failed to resolve API schemas: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), - err instanceof Error ? err : undefined + err instanceof Error ? err : undefined, ); } } else { @@ -205,7 +207,7 @@ export class PgpmModuleSchemaSource implements SchemaSource { throw new SchemaSourceError( `Failed to introspect database: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), - err instanceof Error ? err : undefined + err instanceof Error ? err : undefined, ); } @@ -213,7 +215,7 @@ export class PgpmModuleSchemaSource implements SchemaSource { if (!sdl.trim()) { throw new SchemaSourceError( 'Database introspection returned empty schema', - this.describe() + this.describe(), ); } @@ -225,7 +227,7 @@ export class PgpmModuleSchemaSource implements SchemaSource { throw new SchemaSourceError( `Invalid GraphQL SDL from database: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), - err instanceof Error ? err : undefined + err instanceof Error ? err : undefined, ); } @@ -237,13 +239,13 @@ export class PgpmModuleSchemaSource implements SchemaSource { throw new SchemaSourceError( `Failed to generate introspection: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), - err instanceof Error ? err : undefined + err instanceof Error ? err : undefined, ); } // Convert graphql-js introspection result to our mutable type const introspection: IntrospectionQueryResponse = JSON.parse( - JSON.stringify(introspectionResult) + JSON.stringify(introspectionResult), ) as IntrospectionQueryResponse; return { introspection }; @@ -252,7 +254,9 @@ export class PgpmModuleSchemaSource implements SchemaSource { teardown({ keepDb }); if (keepDb) { - console.log(`[pgpm-module] Kept ephemeral database: ${dbConfig.database}`); + console.log( + `[pgpm-module] Kept ephemeral database: ${dbConfig.database}`, + ); } } } diff --git a/graphql/codegen/src/core/introspect/source/types.ts b/graphql/codegen/src/core/introspect/source/types.ts index 18f301cad..2dfc59234 100644 --- a/graphql/codegen/src/core/introspect/source/types.ts +++ b/graphql/codegen/src/core/introspect/source/types.ts @@ -51,7 +51,7 @@ export class SchemaSourceError extends Error { /** * Original error that caused the failure */ - public readonly cause?: Error + public readonly cause?: Error, ) { super(`${message} (source: ${source})`); this.name = 'SchemaSourceError'; diff --git a/graphql/codegen/src/core/introspect/transform-schema.ts b/graphql/codegen/src/core/introspect/transform-schema.ts index 40cc4aa9f..c872da11c 100644 --- a/graphql/codegen/src/core/introspect/transform-schema.ts +++ b/graphql/codegen/src/core/introspect/transform-schema.ts @@ -5,24 +5,24 @@ * format used by code generators. */ import type { + IntrospectionField, + IntrospectionInputValue, IntrospectionQueryResponse, IntrospectionType, - IntrospectionField, IntrospectionTypeRef, - IntrospectionInputValue, } from '../../types/introspection'; import { - unwrapType, getBaseTypeName, isNonNull, + unwrapType, } from '../../types/introspection'; import type { - CleanOperation, CleanArgument, - CleanTypeRef, CleanObjectField, - TypeRegistry, + CleanOperation, + CleanTypeRef, ResolvedType, + TypeRegistry, } from '../../types/schema'; // ============================================================================ @@ -74,14 +74,14 @@ export function buildTypeRegistry(types: IntrospectionType[]): TypeRegistry { // Resolve fields for OBJECT types if (type.kind === 'OBJECT' && type.fields) { resolvedType.fields = type.fields.map((field) => - transformFieldToCleanObjectFieldShallow(field) + transformFieldToCleanObjectFieldShallow(field), ); } // Resolve input fields for INPUT_OBJECT types if (type.kind === 'INPUT_OBJECT' && type.inputFields) { resolvedType.inputFields = type.inputFields.map((field) => - transformInputValueToCleanArgumentShallow(field) + transformInputValueToCleanArgumentShallow(field), ); } } @@ -94,7 +94,7 @@ export function buildTypeRegistry(types: IntrospectionType[]): TypeRegistry { * (shallow transformation to avoid circular refs) */ function transformFieldToCleanObjectFieldShallow( - field: IntrospectionField + field: IntrospectionField, ): CleanObjectField { return { name: field.name, @@ -107,7 +107,7 @@ function transformFieldToCleanObjectFieldShallow( * Transform input value to CleanArgument without resolving nested types */ function transformInputValueToCleanArgumentShallow( - inputValue: IntrospectionInputValue + inputValue: IntrospectionInputValue, ): CleanArgument { return { name: inputValue.name, @@ -148,7 +148,7 @@ export interface TransformSchemaResult { * Transform introspection response to clean operations */ export function transformSchemaToOperations( - response: IntrospectionQueryResponse + response: IntrospectionQueryResponse, ): TransformSchemaResult { const { __schema: schema } = response; const { types, queryType, mutationType } = schema; @@ -165,14 +165,14 @@ export function transformSchemaToOperations( // Transform queries const queries: CleanOperation[] = queryTypeDef?.fields ? queryTypeDef.fields.map((field) => - transformFieldToCleanOperation(field, 'query', types) + transformFieldToCleanOperation(field, 'query', types), ) : []; // Transform mutations const mutations: CleanOperation[] = mutationTypeDef?.fields ? mutationTypeDef.fields.map((field) => - transformFieldToCleanOperation(field, 'mutation', types) + transformFieldToCleanOperation(field, 'mutation', types), ) : []; @@ -189,13 +189,13 @@ export function transformSchemaToOperations( function transformFieldToCleanOperation( field: IntrospectionField, kind: 'query' | 'mutation', - types: IntrospectionType[] + types: IntrospectionType[], ): CleanOperation { return { name: field.name, kind, args: field.args.map((arg) => - transformInputValueToCleanArgument(arg, types) + transformInputValueToCleanArgument(arg, types), ), returnType: transformTypeRefToCleanTypeRef(field.type, types), description: field.description ?? undefined, @@ -209,7 +209,7 @@ function transformFieldToCleanOperation( */ function transformInputValueToCleanArgument( inputValue: IntrospectionInputValue, - types: IntrospectionType[] + types: IntrospectionType[], ): CleanArgument { return { name: inputValue.name, @@ -233,7 +233,7 @@ function transformInputValueToCleanArgument( */ function transformTypeRefToCleanTypeRef( typeRef: IntrospectionTypeRef, - types: IntrospectionType[] + types: IntrospectionType[], ): CleanTypeRef { const cleanRef: CleanTypeRef = { kind: typeRef.kind as CleanTypeRef['kind'], @@ -273,7 +273,7 @@ function transformTypeRefToCleanTypeRef( export function filterOperations( operations: CleanOperation[], include?: string[], - exclude?: string[] + exclude?: string[], ): CleanOperation[] { let result = operations; @@ -297,7 +297,7 @@ function matchesPatterns(name: string, patterns: string[]): boolean { if (pattern === '*') return true; if (pattern.includes('*')) { const regex = new RegExp( - '^' + pattern.replace(/\*/g, '.*').replace(/\?/g, '.') + '$' + '^' + pattern.replace(/\*/g, '.*').replace(/\?/g, '.') + '$', ); return regex.test(name); } @@ -344,7 +344,7 @@ export function getTableOperationNames( update: string | null; delete: string | null; }; - }> + }>, ): TableOperationNames { const queries = new Set(); const mutations = new Set(); @@ -375,7 +375,7 @@ export function getTableOperationNames( */ export function isTableOperation( operation: CleanOperation, - tableOperationNames: TableOperationNames + tableOperationNames: TableOperationNames, ): boolean { if (operation.kind === 'query') { return tableOperationNames.queries.has(operation.name); @@ -394,10 +394,10 @@ export function isTableOperation( */ export function getCustomOperations( operations: CleanOperation[], - tableOperationNames: TableOperationNames + tableOperationNames: TableOperationNames, ): CleanOperation[] { return operations.filter((op) => !isTableOperation(op, tableOperationNames)); } // Re-export utility functions from introspection types -export { unwrapType, getBaseTypeName, isNonNull }; +export { getBaseTypeName, isNonNull, unwrapType }; diff --git a/graphql/codegen/src/core/introspect/transform.ts b/graphql/codegen/src/core/introspect/transform.ts index 41d8de0f1..95ce1a2e0 100644 --- a/graphql/codegen/src/core/introspect/transform.ts +++ b/graphql/codegen/src/core/introspect/transform.ts @@ -19,7 +19,7 @@ export function getTableNames(tables: CleanTable[]): string[] { */ export function findTable( tables: CleanTable[], - name: string + name: string, ): CleanTable | undefined { return tables.find((t) => t.name === name); } @@ -30,7 +30,7 @@ export function findTable( export function filterTables( tables: CleanTable[], include?: string[], - exclude?: string[] + exclude?: string[], ): CleanTable[] { let result = tables; @@ -53,7 +53,7 @@ function matchesPatterns(name: string, patterns: string[]): boolean { return patterns.some((pattern) => { if (pattern.includes('*')) { const regex = new RegExp( - '^' + pattern.replace(/\*/g, '.*').replace(/\?/g, '.') + '$' + '^' + pattern.replace(/\*/g, '.*').replace(/\?/g, '.') + '$', ); return regex.test(name); } diff --git a/graphql/codegen/src/core/meta-object/convert.ts b/graphql/codegen/src/core/meta-object/convert.ts index 02bff2fe4..72ec26134 100644 --- a/graphql/codegen/src/core/meta-object/convert.ts +++ b/graphql/codegen/src/core/meta-object/convert.ts @@ -75,7 +75,7 @@ interface ConvertedMetaObject { * Convert from raw _meta schema response to internal MetaObject format */ export function convertFromMetaSchema( - metaSchema: MetaSchemaInput + metaSchema: MetaSchemaInput, ): ConvertedMetaObject { const { _meta: { tables }, @@ -93,7 +93,7 @@ export function convertFromMetaSchema( uniqueConstraints: pickArrayConstraint(table.uniqueConstraints), foreignConstraints: pickForeignConstraint( table.foreignKeyConstraints, - table.relations + table.relations, ), }); } @@ -102,7 +102,7 @@ export function convertFromMetaSchema( } function pickArrayConstraint( - constraints: MetaSchemaConstraint[] + constraints: MetaSchemaConstraint[], ): ConvertedConstraint[] { if (constraints.length === 0) return []; const c = constraints[0]; @@ -111,7 +111,7 @@ function pickArrayConstraint( function pickForeignConstraint( constraints: MetaSchemaForeignConstraint[], - relations: MetaSchemaRelations + relations: MetaSchemaRelations, ): ConvertedForeignConstraint[] { if (constraints.length === 0) return []; diff --git a/graphql/codegen/src/core/meta-object/validate.ts b/graphql/codegen/src/core/meta-object/validate.ts index 1481e6b5d..802e0aad1 100644 --- a/graphql/codegen/src/core/meta-object/validate.ts +++ b/graphql/codegen/src/core/meta-object/validate.ts @@ -26,9 +26,7 @@ function getValidator() { * Validate a MetaObject against the JSON schema * @returns true if valid, or an object with errors and message if invalid */ -export function validateMetaObject( - obj: unknown -): true | ValidationResult { +export function validateMetaObject(obj: unknown): true | ValidationResult { const { ajv, validator } = getValidator(); const valid = validator(obj); diff --git a/graphql/codegen/src/core/output/index.ts b/graphql/codegen/src/core/output/index.ts index 3d6344d9c..d5047a2fc 100644 --- a/graphql/codegen/src/core/output/index.ts +++ b/graphql/codegen/src/core/output/index.ts @@ -3,9 +3,9 @@ */ export { - writeGeneratedFiles, formatOutput, type GeneratedFile, - type WriteResult, + writeGeneratedFiles, type WriteOptions, + type WriteResult, } from './writer'; diff --git a/graphql/codegen/src/core/output/writer.ts b/graphql/codegen/src/core/output/writer.ts index 6db930669..630a047d5 100644 --- a/graphql/codegen/src/core/output/writer.ts +++ b/graphql/codegen/src/core/output/writer.ts @@ -17,6 +17,7 @@ export type { GeneratedFile }; export interface WriteResult { success: boolean; filesWritten?: string[]; + filesRemoved?: string[]; errors?: string[]; } @@ -28,12 +29,14 @@ export interface WriteOptions { showProgress?: boolean; /** Format files with oxfmt after writing (default: true) */ formatFiles?: boolean; + /** Remove stale .ts files in outputDir that are not in current file list (default: false) */ + pruneStaleFiles?: boolean; } type OxfmtFormatFn = ( fileName: string, sourceText: string, - options?: Record + options?: Record, ) => Promise<{ code: string; errors: unknown[] }>; /** @@ -55,7 +58,7 @@ async function getOxfmtFormat(): Promise { async function formatFileContent( fileName: string, content: string, - formatFn: OxfmtFormatFn + formatFn: OxfmtFormatFn, ): Promise { try { const result = await formatFn(fileName, content, { @@ -83,11 +86,16 @@ export async function writeGeneratedFiles( files: GeneratedFile[], outputDir: string, subdirs: string[], - options: WriteOptions = {} + options: WriteOptions = {}, ): Promise { - const { showProgress = true, formatFiles = true } = options; + const { + showProgress = true, + formatFiles = true, + pruneStaleFiles = false, + } = options; const errors: string[] = []; const written: string[] = []; + const removed: string[] = []; const total = files.length; const isTTY = process.stdout.isTTY; @@ -117,6 +125,25 @@ export async function writeGeneratedFiles( return { success: false, errors }; } + if (pruneStaleFiles) { + const expectedFiles = new Set( + files.map((file) => path.resolve(outputDir, file.path)), + ); + const existingTsFiles = findTsFiles(outputDir); + + for (const existingFile of existingTsFiles) { + const absolutePath = path.resolve(existingFile); + if (expectedFiles.has(absolutePath)) continue; + try { + fs.rmSync(absolutePath, { force: true }); + removed.push(absolutePath); + } catch (err) { + const message = err instanceof Error ? err.message : 'Unknown error'; + errors.push(`Failed to remove stale file ${absolutePath}: ${message}`); + } + } + } + // Get oxfmt format function if formatting is enabled const formatFn = formatFiles ? await getOxfmtFormat() : null; if (formatFiles && !formatFn && showProgress) { @@ -132,7 +159,7 @@ export async function writeGeneratedFiles( const progress = Math.round(((i + 1) / total) * 100); if (isTTY) { process.stdout.write( - `\rWriting files: ${i + 1}/${total} (${progress}%)` + `\rWriting files: ${i + 1}/${total} (${progress}%)`, ); } else if (i % 100 === 0 || i === total - 1) { // Non-TTY: periodic updates for CI/CD @@ -171,6 +198,7 @@ export async function writeGeneratedFiles( return { success: errors.length === 0, filesWritten: written, + filesRemoved: removed, errors: errors.length > 0 ? errors : undefined, }; } @@ -205,7 +233,7 @@ function findTsFiles(dir: string): string[] { * This function is kept for backwards compatibility. */ export async function formatOutput( - outputDir: string + outputDir: string, ): Promise<{ success: boolean; error?: string }> { const formatFn = await getOxfmtFormat(); if (!formatFn) { @@ -223,7 +251,11 @@ export async function formatOutput( for (const filePath of tsFiles) { const content = fs.readFileSync(filePath, 'utf-8'); - const formatted = await formatFileContent(path.basename(filePath), content, formatFn); + const formatted = await formatFileContent( + path.basename(filePath), + content, + formatFn, + ); fs.writeFileSync(filePath, formatted, 'utf-8'); } diff --git a/graphql/codegen/src/core/pipeline/index.ts b/graphql/codegen/src/core/pipeline/index.ts index 65aba4e21..55ba15cee 100644 --- a/graphql/codegen/src/core/pipeline/index.ts +++ b/graphql/codegen/src/core/pipeline/index.ts @@ -10,23 +10,26 @@ */ import type { GraphQLSDKConfigTarget } from '../../types/config'; import type { - CleanTable, CleanOperation, + CleanTable, TypeRegistry, } from '../../types/schema'; -import type { SchemaSource } from '../introspect/source'; import { inferTablesFromIntrospection } from '../introspect/infer-tables'; +import type { SchemaSource } from '../introspect/source'; import { filterTables } from '../introspect/transform'; import { - transformSchemaToOperations, filterOperations, - getTableOperationNames, getCustomOperations, + getTableOperationNames, + transformSchemaToOperations, } from '../introspect/transform-schema'; // Re-export for convenience export type { SchemaSource } from '../introspect/source'; -export { createSchemaSource, validateSourceOptions } from '../introspect/source'; +export { + createSchemaSource, + validateSourceOptions, +} from '../introspect/source'; // ============================================================================ // Pipeline Types @@ -97,7 +100,7 @@ export interface CodegenPipelineResult { * 5. Separate table operations from custom operations */ export async function runCodegenPipeline( - options: CodegenPipelineOptions + options: CodegenPipelineOptions, ): Promise { const { source, @@ -149,27 +152,27 @@ export async function runCodegenPipeline( const filteredQueries = filterOperations( allQueries, config.queries.include, - [...config.queries.exclude, ...config.queries.systemExclude] + [...config.queries.exclude, ...config.queries.systemExclude], ); const filteredMutations = filterOperations( allMutations, config.mutations.include, - [...config.mutations.exclude, ...config.mutations.systemExclude] + [...config.mutations.exclude, ...config.mutations.systemExclude], ); log( - ` After config filtering: ${filteredQueries.length} queries, ${filteredMutations.length} mutations` + ` After config filtering: ${filteredQueries.length} queries, ${filteredMutations.length} mutations`, ); // Remove table operations (already handled by table generators) customQueries = getCustomOperations(filteredQueries, tableOperationNames); customMutations = getCustomOperations( filteredMutations, - tableOperationNames + tableOperationNames, ); log( - ` Custom operations: ${customQueries.length} queries, ${customMutations.length} mutations` + ` Custom operations: ${customQueries.length} queries, ${customMutations.length} mutations`, ); } diff --git a/graphql/codegen/src/core/query-builder.ts b/graphql/codegen/src/core/query-builder.ts index 8be4db4ca..7d6bbbe5d 100644 --- a/graphql/codegen/src/core/query-builder.ts +++ b/graphql/codegen/src/core/query-builder.ts @@ -1,5 +1,5 @@ import { DocumentNode, print as gqlPrint } from 'graphql'; -import { camelize, underscore, pluralize } from 'inflekt'; +import { camelize, pluralize, underscore } from 'inflekt'; import { createOne, @@ -12,7 +12,6 @@ import { } from './ast'; import { validateMetaObject } from './meta-object'; import type { - QueryFieldSelection, IntrospectionSchema, MetaObject, MetaTable, @@ -20,6 +19,7 @@ import type { QueryBuilderOptions, QueryBuilderResult, QueryDefinition, + QueryFieldSelection, QuerySelectionOptions, } from './types'; @@ -44,10 +44,7 @@ export class QueryBuilder { private _mutation!: string; private _select!: QueryFieldSelection[]; - constructor({ - meta = {} as MetaObject, - introspection, - }: QueryBuilderOptions) { + constructor({ meta = {} as MetaObject, introspection }: QueryBuilderOptions) { this._introspection = introspection; this._meta = meta; this.clear(); @@ -58,7 +55,7 @@ export class QueryBuilder { const result = validateMetaObject(this._meta); if (typeof result === 'object' && result.errors) { throw new Error( - `QueryBuilder: meta object is invalid:\n${result.message}` + `QueryBuilder: meta object is invalid:\n${result.message}`, ); } } @@ -67,7 +64,10 @@ export class QueryBuilder { * Save all gql queries and mutations by model name for quicker lookup */ initModelMap(): void { - this._models = {} as Record>; + this._models = {} as Record< + string, + Record + >; for (const [key, defn] of Object.entries(this._introspection)) { if (!this._models[defn.model]) { @@ -102,7 +102,7 @@ export class QueryBuilder { } const matchQuery = Object.entries(queries).find( - ([_, defn]) => defn.qtype === this._op + ([_, defn]) => defn.qtype === this._op, ); if (!matchQuery) { @@ -132,12 +132,12 @@ export class QueryBuilder { [] as Array<{ defn: QueryDefinition | MutationDefinition; mutationKey: string; - }> + }>, ); if (matchingDefns.length === 0) { throw new Error( - 'no mutation found for ' + this._model + ':' + this._mutation + 'no mutation found for ' + this._model + ':' + this._mutation, ); } @@ -159,12 +159,12 @@ export class QueryBuilder { }; const matchDefn = matchingDefns.find( - ({ defn }) => defn.properties.input.type === getInputName(this._mutation) + ({ defn }) => defn.properties.input.type === getInputName(this._mutation), ); if (!matchDefn) { throw new Error( - 'no mutation found for ' + this._model + ':' + this._mutation + 'no mutation found for ' + this._model + ':' + this._mutation, ); } @@ -194,10 +194,7 @@ export class QueryBuilder { this._key = this._findQuery(); this.queryName( - camelize( - ['get', underscore(this._key), 'query'].join('_'), - true - ) + camelize(['get', underscore(this._key), 'query'].join('_'), true), ); const defn = this._introspection[this._key]; @@ -219,10 +216,7 @@ export class QueryBuilder { this._key = this._findQuery(); this.queryName( - camelize( - ['get', underscore(this._key), 'query', 'all'].join('_'), - true - ) + camelize(['get', underscore(this._key), 'query', 'all'].join('_'), true), ); const defn = this._introspection[this._key]; @@ -245,8 +239,8 @@ export class QueryBuilder { this.queryName( camelize( ['get', underscore(this._key), 'count', 'query'].join('_'), - true - ) + true, + ), ); const defn = this._introspection[this._key]; @@ -265,10 +259,7 @@ export class QueryBuilder { this._key = this._findQuery(); this.queryName( - camelize( - ['get', underscore(this._key), 'query'].join('_'), - true - ) + camelize(['get', underscore(this._key), 'query'].join('_'), true), ); const defn = this._introspection[this._key]; @@ -290,10 +281,7 @@ export class QueryBuilder { this._key = this._findMutation(); this.queryName( - camelize( - [underscore(this._key), 'mutation'].join('_'), - true - ) + camelize([underscore(this._key), 'mutation'].join('_'), true), ); const defn = this._introspection[this._key] as MutationDefinition; @@ -314,10 +302,7 @@ export class QueryBuilder { this._key = this._findMutation(); this.queryName( - camelize( - [underscore(this._key), 'mutation'].join('_'), - true - ) + camelize([underscore(this._key), 'mutation'].join('_'), true), ); const defn = this._introspection[this._key] as MutationDefinition; @@ -338,10 +323,7 @@ export class QueryBuilder { this._key = this._findMutation(); this.queryName( - camelize( - [underscore(this._key), 'mutation'].join('_'), - true - ) + camelize([underscore(this._key), 'mutation'].join('_'), true), ); const defn = this._introspection[this._key] as MutationDefinition; @@ -377,11 +359,11 @@ export class QueryBuilder { // Bind methods that will be called with different this context pickScalarFields: ( selection: QuerySelectionOptions | null, - defn: QueryDefinition + defn: QueryDefinition, ) => QueryFieldSelection[]; pickAllFields: ( selection: QuerySelectionOptions, - defn: QueryDefinition + defn: QueryDefinition, ) => QueryFieldSelection[]; } @@ -394,7 +376,7 @@ export class QueryBuilder { function pickScalarFields( this: QueryBuilder, selection: QuerySelectionOptions | null, - defn: QueryDefinition + defn: QueryDefinition, ): QueryFieldSelection[] { const model = defn.model; const modelMeta = this._meta.tables.find((t) => t.name === model); @@ -416,7 +398,7 @@ function pickScalarFields( .filter( (fieldName) => !isRelationalField(fieldName, modelMeta) && - isInTableSchema(fieldName) + isInTableSchema(fieldName), ) .map((fieldName) => ({ name: fieldName, @@ -445,7 +427,7 @@ function pickScalarFields( function pickAllFields( this: QueryBuilder, selection: QuerySelectionOptions, - defn: QueryDefinition + defn: QueryDefinition, ): QueryFieldSelection[] { const model = defn.model; const modelMeta = this._meta.tables.find((t) => t.name === model); @@ -476,7 +458,7 @@ function pickAllFields( const referencedForeignConstraint = modelMeta.foreignConstraints.find( (constraint) => constraint.fromKey.name === fieldName || - constraint.fromKey.alias === fieldName + constraint.fromKey.alias === fieldName, ); const selectOptions = fieldOptions as { @@ -507,13 +489,13 @@ function pickAllFields( // location is non-scalar and non-relational, thus need to further expand into { x y ... } if (isBelongTo) { const getManyName = modelNameToGetMany( - referencedForeignConstraint.refTable + referencedForeignConstraint.refTable, ); const refDefn = this._introspection[getManyName]; fieldSelection.selection = pickScalarFields.call( this, { [fieldName]: true }, - refDefn + refDefn, ); } @@ -542,12 +524,12 @@ function pickAllFields( function isFieldInDefinition( fieldName: string, defn: QueryDefinition, - modelMeta: MetaTable + modelMeta: MetaTable, ): boolean { const isReferenced = !!modelMeta.foreignConstraints.find( (constraint) => constraint.fromKey.name === fieldName || - constraint.fromKey.alias === fieldName + constraint.fromKey.alias === fieldName, ); return ( @@ -570,7 +552,7 @@ function isRelationalField(fieldName: string, modelMeta: MetaTable): boolean { return ( !modelMeta.primaryConstraints.find((field) => field.name === fieldName) && !!modelMeta.foreignConstraints.find( - (constraint) => constraint.fromKey.name === fieldName + (constraint) => constraint.fromKey.name === fieldName, ) ); } @@ -578,8 +560,5 @@ function isRelationalField(fieldName: string, modelMeta: MetaTable): boolean { // Get getMany op name from model // ie. UserSetting => userSettings function modelNameToGetMany(model: string): string { - return camelize( - pluralize(underscore(model)), - true - ); + return camelize(pluralize(underscore(model)), true); } diff --git a/graphql/codegen/src/core/types.ts b/graphql/codegen/src/core/types.ts index fc9b252e3..f3fc365a6 100644 --- a/graphql/codegen/src/core/types.ts +++ b/graphql/codegen/src/core/types.ts @@ -1,9 +1,18 @@ -import type { DocumentNode, FieldNode, SelectionSetNode, VariableDefinitionNode } from 'graphql'; +import type { + DocumentNode, + FieldNode, + SelectionSetNode, + VariableDefinitionNode, +} from 'graphql'; import type { CleanField } from '../types/schema'; // GraphQL AST types (re-export what we need from gql-ast) -export type ASTNode = DocumentNode | FieldNode | SelectionSetNode | VariableDefinitionNode; +export type ASTNode = + | DocumentNode + | FieldNode + | SelectionSetNode + | VariableDefinitionNode; // Nested property structure for complex mutation inputs export interface NestedProperties { @@ -164,7 +173,7 @@ export interface ObjectArrayItem extends QueryProperty { // Type guards for runtime validation export function isGraphQLVariableValue( - value: unknown + value: unknown, ): value is GraphQLVariableValue { return ( value === null || @@ -183,7 +192,7 @@ export function isGraphQLVariables(obj: unknown): obj is GraphQLVariables { if (Array.isArray(value)) { if ( !value.every( - (item) => isGraphQLVariableValue(item) || isGraphQLVariables(item) + (item) => isGraphQLVariableValue(item) || isGraphQLVariables(item), ) ) { return false; diff --git a/graphql/codegen/src/core/watch/cache.ts b/graphql/codegen/src/core/watch/cache.ts index f92764d02..0b23a7db6 100644 --- a/graphql/codegen/src/core/watch/cache.ts +++ b/graphql/codegen/src/core/watch/cache.ts @@ -7,6 +7,7 @@ import * as fs from 'node:fs'; import * as path from 'node:path'; + import type { IntrospectionQueryResponse } from '../../types/introspection'; import { hashObject } from './hash'; @@ -23,7 +24,7 @@ export class SchemaCache { * This is the hot path - must be efficient */ async hasChanged( - schema: IntrospectionQueryResponse + schema: IntrospectionQueryResponse, ): Promise<{ changed: boolean; newHash: string }> { const newHash = await this.computeHash(schema); const changed = this.currentHash === null || this.currentHash !== newHash; @@ -55,7 +56,7 @@ export class SchemaCache { * Compute hash from schema response */ private async computeHash( - schema: IntrospectionQueryResponse + schema: IntrospectionQueryResponse, ): Promise { return hashObject(schema); } diff --git a/graphql/codegen/src/core/watch/debounce.ts b/graphql/codegen/src/core/watch/debounce.ts index 93d06a21f..cf5d15de6 100644 --- a/graphql/codegen/src/core/watch/debounce.ts +++ b/graphql/codegen/src/core/watch/debounce.ts @@ -8,7 +8,7 @@ */ export function debounce unknown>( func: T, - wait: number + wait: number, ): { (...args: Parameters): void; cancel: () => void; @@ -56,9 +56,11 @@ export function debounce unknown>( /** * Creates an async debounced function */ -export function debounceAsync Promise>( +export function debounceAsync< + T extends (...args: unknown[]) => Promise, +>( func: T, - wait: number + wait: number, ): { (...args: Parameters): Promise; cancel: () => void; diff --git a/graphql/codegen/src/core/watch/hash.ts b/graphql/codegen/src/core/watch/hash.ts index 75d3443b9..2f5aa99ca 100644 --- a/graphql/codegen/src/core/watch/hash.ts +++ b/graphql/codegen/src/core/watch/hash.ts @@ -37,7 +37,7 @@ function sortReplacer(_key: string, value: unknown): unknown { sorted[key] = (value as Record)[key]; return sorted; }, - {} as Record + {} as Record, ); } return value; diff --git a/graphql/codegen/src/core/watch/index.ts b/graphql/codegen/src/core/watch/index.ts index 6e220682f..a1f3fe6f2 100644 --- a/graphql/codegen/src/core/watch/index.ts +++ b/graphql/codegen/src/core/watch/index.ts @@ -2,17 +2,17 @@ * Watch mode module exports */ -export { SchemaPoller, computeSchemaHash } from './poller'; export { SchemaCache, touchFile } from './cache'; -export { sha256, hashObject, combineHashes } from './hash'; export { debounce, debounceAsync } from './debounce'; -export { WatchOrchestrator, startWatch } from './orchestrator'; +export { combineHashes, hashObject, sha256 } from './hash'; +export type { WatchOrchestratorOptions, WatchStatus } from './orchestrator'; +export { startWatch, WatchOrchestrator } from './orchestrator'; +export { computeSchemaHash, SchemaPoller } from './poller'; export type { + GeneratorType, + PollEvent, + PollEventHandler, + PollEventType, PollResult, WatchOptions, - PollEventType, - PollEventHandler, - PollEvent, - GeneratorType, } from './types'; -export type { WatchOrchestratorOptions, WatchStatus } from './orchestrator'; diff --git a/graphql/codegen/src/core/watch/orchestrator.ts b/graphql/codegen/src/core/watch/orchestrator.ts index c530c113e..93f1f8a80 100644 --- a/graphql/codegen/src/core/watch/orchestrator.ts +++ b/graphql/codegen/src/core/watch/orchestrator.ts @@ -5,9 +5,9 @@ */ import type { GraphQLSDKConfigTarget } from '../../types/config'; -import type { GeneratorType, WatchOptions, PollEvent } from './types'; -import { SchemaPoller } from './poller'; import { debounce } from './debounce'; +import { SchemaPoller } from './poller'; +import type { GeneratorType, PollEvent, WatchOptions } from './types'; // These will be injected by the CLI layer to avoid circular dependencies // The watch orchestrator doesn't need to know about the full generate commands @@ -88,7 +88,7 @@ export class WatchOrchestrator { // Create debounced regenerate function this.debouncedRegenerate = debounce( () => this.regenerate(), - options.config.watch.debounce + options.config.watch.debounce, ); // Set up event handlers @@ -172,7 +172,7 @@ export class WatchOrchestrator { // Start polling loop this.poller.start(); this.log( - `Watching for schema changes (poll interval: ${this.watchOptions.pollInterval}ms)` + `Watching for schema changes (poll interval: ${this.watchOptions.pollInterval}ms)`, ); } @@ -220,15 +220,19 @@ export class WatchOrchestrator { case 'react-query': generateFn = this.options.generateReactQuery; // React Query hooks go to {output}/hooks - outputDir = this.options.outputDir ?? `${this.options.config.output}/hooks`; + outputDir = + this.options.outputDir ?? `${this.options.config.output}/hooks`; break; case 'orm': generateFn = this.options.generateOrm; // ORM client goes to {output}/orm - outputDir = this.options.outputDir ?? `${this.options.config.output}/orm`; + outputDir = + this.options.outputDir ?? `${this.options.config.output}/orm`; break; default: - throw new Error(`Unknown generator type: ${this.options.generatorType}`); + throw new Error( + `Unknown generator type: ${this.options.generatorType}`, + ); } const result = await generateFn({ @@ -294,7 +298,9 @@ export class WatchOrchestrator { generatorName = 'ORM client'; break; default: - throw new Error(`Unknown generator type: ${this.options.generatorType}`); + throw new Error( + `Unknown generator type: ${this.options.generatorType}`, + ); } console.log(`\n${'─'.repeat(50)}`); console.log(`graphql-codegen watch mode (${generatorName})`); @@ -322,7 +328,7 @@ export class WatchOrchestrator { * Start watch mode for a generator */ export async function startWatch( - options: WatchOrchestratorOptions + options: WatchOrchestratorOptions, ): Promise { const orchestrator = new WatchOrchestrator(options); await orchestrator.start(); diff --git a/graphql/codegen/src/core/watch/poller.ts b/graphql/codegen/src/core/watch/poller.ts index c60583f85..1851e5e3f 100644 --- a/graphql/codegen/src/core/watch/poller.ts +++ b/graphql/codegen/src/core/watch/poller.ts @@ -6,16 +6,17 @@ */ import { EventEmitter } from 'node:events'; + import type { IntrospectionQueryResponse } from '../../types/introspection'; import { fetchSchema } from '../introspect/fetch-schema'; import { SchemaCache, touchFile } from './cache'; +import { hashObject } from './hash'; import type { - PollResult, PollEvent, PollEventType, + PollResult, WatchOptions, } from './types'; -import { hashObject } from './hash'; /** * Schema poller that periodically introspects a GraphQL endpoint @@ -96,7 +97,7 @@ export class SchemaPoller extends EventEmitter { if (!schemaResult.success) { return this.handleError( `__schema fetch failed: ${schemaResult.error}`, - duration + duration, ); } @@ -119,14 +120,14 @@ export class SchemaPoller extends EventEmitter { this.emit( 'schema-changed', - this.createEvent('schema-changed', { hash: newHash, duration }) + this.createEvent('schema-changed', { hash: newHash, duration }), ); return { success: true, changed: true, hash: newHash, schema }; } this.emit( 'schema-unchanged', - this.createEvent('schema-unchanged', { duration }) + this.createEvent('schema-unchanged', { duration }), ); this.emit('poll-success', this.createEvent('poll-success', { duration })); return { success: true, changed: false, hash: newHash, schema }; @@ -193,7 +194,7 @@ export class SchemaPoller extends EventEmitter { this.consecutiveErrors++; this.emit( 'poll-error', - this.createEvent('poll-error', { error, duration }) + this.createEvent('poll-error', { error, duration }), ); // Slow down polling after multiple consecutive errors @@ -213,7 +214,7 @@ export class SchemaPoller extends EventEmitter { private createEvent( type: PollEventType, - extra?: Partial + extra?: Partial, ): PollEvent { return { type, @@ -227,7 +228,7 @@ export class SchemaPoller extends EventEmitter { * Utility to compute schema hash without full poll */ export async function computeSchemaHash( - schema: IntrospectionQueryResponse + schema: IntrospectionQueryResponse, ): Promise { return hashObject(schema); } diff --git a/graphql/codegen/src/generators/field-selector.ts b/graphql/codegen/src/generators/field-selector.ts index 8e42e5c9d..a4e23f115 100644 --- a/graphql/codegen/src/generators/field-selector.ts +++ b/graphql/codegen/src/generators/field-selector.ts @@ -16,7 +16,7 @@ import type { export function convertToSelectionOptions( table: CleanTable, allTables: CleanTable[], - selection?: FieldSelection + selection?: FieldSelection, ): QuerySelectionOptions | null { if (!selection) { return convertPresetToSelection(table, 'display'); @@ -34,7 +34,7 @@ export function convertToSelectionOptions( */ function convertPresetToSelection( table: CleanTable, - preset: FieldSelectionPreset + preset: FieldSelectionPreset, ): QuerySelectionOptions { const options: QuerySelectionOptions = {}; @@ -91,7 +91,7 @@ function convertPresetToSelection( function convertCustomSelectionToOptions( table: CleanTable, allTables: CleanTable[], - selection: SimpleFieldSelection + selection: SimpleFieldSelection, ): QuerySelectionOptions { const options: QuerySelectionOptions = {}; @@ -135,7 +135,7 @@ function convertCustomSelectionToOptions( select: getRelatedTableScalarFields( relationField, table, - allTables + allTables, ), variables: {}, }; @@ -151,7 +151,7 @@ function convertCustomSelectionToOptions( }; } } - } + }, ); } @@ -188,7 +188,7 @@ function getDisplayFields(table: CleanTable): string[] { // This is completely dynamic based on what the schema actually provides const maxDisplayFields = Math.max( 5, - Math.floor(nonRelationalFields.length / 2) + Math.floor(nonRelationalFields.length / 2), ); return nonRelationalFields.slice(0, maxDisplayFields); } @@ -208,7 +208,7 @@ function getNonRelationalFields(table: CleanTable): string[] { */ export function isRelationalField( fieldName: string, - table: CleanTable + table: CleanTable, ): boolean { const { belongsTo, hasOne, hasMany, manyToMany } = table.relations; @@ -227,14 +227,14 @@ export function isRelationalField( function getRelatedTableScalarFields( relationField: string, table: CleanTable, - allTables: CleanTable[] + allTables: CleanTable[], ): Record { // Find the related table name let referencedTableName: string | undefined; // Check belongsTo relations const belongsToRel = table.relations.belongsTo.find( - (rel) => rel.fieldName === relationField + (rel) => rel.fieldName === relationField, ); if (belongsToRel) { referencedTableName = belongsToRel.referencesTable; @@ -243,7 +243,7 @@ function getRelatedTableScalarFields( // Check hasOne relations if (!referencedTableName) { const hasOneRel = table.relations.hasOne.find( - (rel) => rel.fieldName === relationField + (rel) => rel.fieldName === relationField, ); if (hasOneRel) { referencedTableName = hasOneRel.referencedByTable; @@ -253,7 +253,7 @@ function getRelatedTableScalarFields( // Check hasMany relations if (!referencedTableName) { const hasManyRel = table.relations.hasMany.find( - (rel) => rel.fieldName === relationField + (rel) => rel.fieldName === relationField, ); if (hasManyRel) { referencedTableName = hasManyRel.referencedByTable; @@ -263,7 +263,7 @@ function getRelatedTableScalarFields( // Check manyToMany relations if (!referencedTableName) { const manyToManyRel = table.relations.manyToMany.find( - (rel) => rel.fieldName === relationField + (rel) => rel.fieldName === relationField, ); if (manyToManyRel) { referencedTableName = manyToManyRel.rightTable; @@ -332,9 +332,7 @@ function getRelatedTableScalarFields( /** * Get all available relation fields from a table */ -export function getAvailableRelations( - table: CleanTable -): Array<{ +export function getAvailableRelations(table: CleanTable): Array<{ fieldName: string; type: 'belongsTo' | 'hasOne' | 'hasMany' | 'manyToMany'; referencedTable?: string; @@ -397,7 +395,7 @@ export function getAvailableRelations( */ export function validateFieldSelection( selection: FieldSelection, - table: CleanTable + table: CleanTable, ): { isValid: boolean; errors: string[] } { const errors: string[] = []; @@ -412,9 +410,7 @@ export function validateFieldSelection( if (selection.select) { selection.select.forEach((field) => { if (!tableFieldNames.includes(field)) { - errors.push( - `Field '${field}' does not exist in table '${table.name}'` - ); + errors.push(`Field '${field}' does not exist in table '${table.name}'`); } }); } @@ -424,7 +420,7 @@ export function validateFieldSelection( selection.includeRelations.forEach((field) => { if (!isRelationalField(field, table)) { errors.push( - `Field '${field}' is not a relational field in table '${table.name}'` + `Field '${field}' is not a relational field in table '${table.name}'`, ); } }); @@ -435,7 +431,7 @@ export function validateFieldSelection( Object.keys(selection.include).forEach((field) => { if (!isRelationalField(field, table)) { errors.push( - `Field '${field}' is not a relational field in table '${table.name}'` + `Field '${field}' is not a relational field in table '${table.name}'`, ); } }); @@ -446,7 +442,7 @@ export function validateFieldSelection( selection.exclude.forEach((field) => { if (!tableFieldNames.includes(field)) { errors.push( - `Exclude field '${field}' does not exist in table '${table.name}'` + `Exclude field '${field}' does not exist in table '${table.name}'`, ); } }); diff --git a/graphql/codegen/src/generators/index.ts b/graphql/codegen/src/generators/index.ts index 1bc3c755e..d4420dfee 100644 --- a/graphql/codegen/src/generators/index.ts +++ b/graphql/codegen/src/generators/index.ts @@ -5,26 +5,26 @@ // Field selector utilities export { convertToSelectionOptions, - isRelationalField, getAvailableRelations, + isRelationalField, validateFieldSelection, } from './field-selector'; // Query generators export { - buildSelect, - buildFindOne, buildCount, - toCamelCasePlural, - toOrderByTypeName, + buildFindOne, + buildSelect, cleanTableToMetaObject, - generateIntrospectionSchema, createASTQueryBuilder, + generateIntrospectionSchema, + toCamelCasePlural, + toOrderByTypeName, } from './select'; // Mutation generators export { buildPostGraphileCreate, - buildPostGraphileUpdate, buildPostGraphileDelete, + buildPostGraphileUpdate, } from './mutations'; diff --git a/graphql/codegen/src/generators/mutations.ts b/graphql/codegen/src/generators/mutations.ts index a7d495e0b..7e5b2ea97 100644 --- a/graphql/codegen/src/generators/mutations.ts +++ b/graphql/codegen/src/generators/mutations.ts @@ -3,8 +3,8 @@ * Uses AST-based approach for PostGraphile-compatible mutations */ import * as t from 'gql-ast'; -import { print } from 'graphql'; import type { ArgumentNode, FieldNode, VariableDefinitionNode } from 'graphql'; +import { print } from 'graphql'; import { camelize } from 'inflekt'; import { TypedDocumentString } from '../client/typed-document'; @@ -12,9 +12,8 @@ import { getCustomAstForCleanField, requiresSubfieldSelection, } from '../core/custom-ast'; -import type { CleanTable } from '../types/schema'; import type { MutationOptions } from '../types/mutation'; - +import type { CleanTable } from '../types/schema'; import { isRelationalField } from './field-selector'; /** @@ -42,7 +41,7 @@ function generateFieldSelections(table: CleanTable): FieldNode[] { export function buildPostGraphileCreate( table: CleanTable, _allTables: CleanTable[], - _options: MutationOptions = {} + _options: MutationOptions = {}, ): TypedDocumentString< Record, { input: { [key: string]: Record } } @@ -118,7 +117,7 @@ export function buildPostGraphileCreate( export function buildPostGraphileUpdate( table: CleanTable, _allTables: CleanTable[], - _options: MutationOptions = {} + _options: MutationOptions = {}, ): TypedDocumentString< Record, { input: { id: string | number; patch: Record } } @@ -194,7 +193,7 @@ export function buildPostGraphileUpdate( export function buildPostGraphileDelete( table: CleanTable, _allTables: CleanTable[], - _options: MutationOptions = {} + _options: MutationOptions = {}, ): TypedDocumentString< Record, { input: { id: string | number } } diff --git a/graphql/codegen/src/generators/select.ts b/graphql/codegen/src/generators/select.ts index edf2cace7..493eac8f0 100644 --- a/graphql/codegen/src/generators/select.ts +++ b/graphql/codegen/src/generators/select.ts @@ -3,8 +3,8 @@ * Uses AST-based approach for all query generation */ import * as t from 'gql-ast'; -import { print } from 'graphql'; import type { ArgumentNode, FieldNode, VariableDefinitionNode } from 'graphql'; +import { print } from 'graphql'; import { camelize, pluralize } from 'inflekt'; import { TypedDocumentString } from '../client/typed-document'; @@ -22,10 +22,9 @@ import type { QueryDefinition, QuerySelectionOptions, } from '../core/types'; -import type { CleanTable } from '../types/schema'; import type { QueryOptions } from '../types/query'; +import type { CleanTable } from '../types/schema'; import type { FieldSelection } from '../types/selection'; - import { convertToSelectionOptions, isRelationalField } from './field-selector'; /** @@ -109,7 +108,7 @@ export function cleanTableToMetaObject(tables: CleanTable[]): MetaObject { * This creates a minimal schema for AST generation */ export function generateIntrospectionSchema( - tables: CleanTable[] + tables: CleanTable[], ): IntrospectionSchema { const schema: IntrospectionSchema = {}; @@ -279,13 +278,13 @@ export function createASTQueryBuilder(tables: CleanTable[]): QueryBuilder { export function buildSelect( table: CleanTable, allTables: readonly CleanTable[], - options: QueryOptions = {} + options: QueryOptions = {}, ): TypedDocumentString, QueryOptions> { const tableList = Array.from(allTables); const selection = convertFieldSelectionToSelectionOptions( table, tableList, - options.fieldSelection + options.fieldSelection, ); // Generate query directly using AST @@ -293,7 +292,7 @@ export function buildSelect( table, tableList, selection, - options + options, ); return new TypedDocumentString(queryString, {}) as TypedDocumentString< @@ -307,7 +306,7 @@ export function buildSelect( */ export function buildFindOne( table: CleanTable, - _pkField: string = 'id' + _pkField: string = 'id', ): TypedDocumentString, Record> { const queryString = generateFindOneQueryAST(table); @@ -321,7 +320,7 @@ export function buildFindOne( * Build a count query for a table */ export function buildCount( - table: CleanTable + table: CleanTable, ): TypedDocumentString< { [key: string]: { totalCount: number } }, { condition?: Record; filter?: Record } @@ -337,7 +336,7 @@ export function buildCount( function convertFieldSelectionToSelectionOptions( table: CleanTable, allTables: CleanTable[], - options?: FieldSelection + options?: FieldSelection, ): QuerySelectionOptions | null { return convertToSelectionOptions(table, allTables, options); } @@ -349,7 +348,7 @@ function generateSelectQueryAST( table: CleanTable, allTables: CleanTable[], selection: QuerySelectionOptions | null, - options: QueryOptions + options: QueryOptions, ): string { const pluralName = toCamelCasePlural(table.name); @@ -357,7 +356,7 @@ function generateSelectQueryAST( const fieldSelections = generateFieldSelectionsFromOptions( table, allTables, - selection + selection, ); // Build the query AST @@ -371,13 +370,13 @@ function generateSelectQueryAST( t.variableDefinition({ variable: t.variable({ name: 'first' }), type: t.namedType({ type: 'Int' }), - }) + }), ); queryArgs.push( t.argument({ name: 'first', value: t.variable({ name: 'first' }), - }) + }), ); } @@ -386,13 +385,13 @@ function generateSelectQueryAST( t.variableDefinition({ variable: t.variable({ name: 'offset' }), type: t.namedType({ type: 'Int' }), - }) + }), ); queryArgs.push( t.argument({ name: 'offset', value: t.variable({ name: 'offset' }), - }) + }), ); } @@ -402,13 +401,13 @@ function generateSelectQueryAST( t.variableDefinition({ variable: t.variable({ name: 'after' }), type: t.namedType({ type: 'Cursor' }), - }) + }), ); queryArgs.push( t.argument({ name: 'after', value: t.variable({ name: 'after' }), - }) + }), ); } @@ -417,13 +416,13 @@ function generateSelectQueryAST( t.variableDefinition({ variable: t.variable({ name: 'before' }), type: t.namedType({ type: 'Cursor' }), - }) + }), ); queryArgs.push( t.argument({ name: 'before', value: t.variable({ name: 'before' }), - }) + }), ); } @@ -433,13 +432,13 @@ function generateSelectQueryAST( t.variableDefinition({ variable: t.variable({ name: 'filter' }), type: t.namedType({ type: `${table.name}Filter` }), - }) + }), ); queryArgs.push( t.argument({ name: 'filter', value: t.variable({ name: 'filter' }), - }) + }), ); } @@ -454,13 +453,13 @@ function generateSelectQueryAST( type: t.namedType({ type: toOrderByTypeName(table.name) }), }), }), - }) + }), ); queryArgs.push( t.argument({ name: 'orderBy', value: t.variable({ name: 'orderBy' }), - }) + }), ); } @@ -492,7 +491,7 @@ function generateSelectQueryAST( t.field({ name: 'endCursor' }), ], }), - }) + }), ); } @@ -526,7 +525,7 @@ function generateSelectQueryAST( function generateFieldSelectionsFromOptions( table: CleanTable, allTables: CleanTable[], - selection: QuerySelectionOptions | null + selection: QuerySelectionOptions | null, ): FieldNode[] { const DEFAULT_NESTED_RELATION_FIRST = 20; @@ -569,7 +568,7 @@ function generateFieldSelectionsFromOptions( if (include) { // Check if this nested field requires subfield selection const nestedFieldDef = relatedTable?.fields.find( - (f) => f.name === nestedField + (f) => f.name === nestedField, ); if (nestedFieldDef && requiresSubfieldSelection(nestedFieldDef)) { // Use custom AST generation for complex nested fields @@ -609,7 +608,7 @@ function generateFieldSelectionsFromOptions( }), ], }), - }) + }), ); } else { // For belongsTo/hasOne relations, use direct selection @@ -619,7 +618,7 @@ function generateFieldSelectionsFromOptions( selectionSet: t.selectionSet({ selections: nestedSelections, }), - }) + }), ); } } @@ -633,7 +632,7 @@ function generateFieldSelectionsFromOptions( */ function getRelationInfo( fieldName: string, - table: CleanTable + table: CleanTable, ): { type: string; relation: unknown } | null { const { belongsTo, hasOne, hasMany, manyToMany } = table.relations; @@ -670,14 +669,14 @@ function getRelationInfo( function findRelatedTable( relationField: string, table: CleanTable, - allTables: CleanTable[] + allTables: CleanTable[], ): CleanTable | null { // Find the related table name let referencedTableName: string | undefined; // Check belongsTo relations const belongsToRel = table.relations.belongsTo.find( - (rel) => rel.fieldName === relationField + (rel) => rel.fieldName === relationField, ); if (belongsToRel) { referencedTableName = belongsToRel.referencesTable; @@ -686,7 +685,7 @@ function findRelatedTable( // Check hasOne relations if (!referencedTableName) { const hasOneRel = table.relations.hasOne.find( - (rel) => rel.fieldName === relationField + (rel) => rel.fieldName === relationField, ); if (hasOneRel) { referencedTableName = hasOneRel.referencedByTable; @@ -696,7 +695,7 @@ function findRelatedTable( // Check hasMany relations if (!referencedTableName) { const hasManyRel = table.relations.hasMany.find( - (rel) => rel.fieldName === relationField + (rel) => rel.fieldName === relationField, ); if (hasManyRel) { referencedTableName = hasManyRel.referencedByTable; @@ -706,7 +705,7 @@ function findRelatedTable( // Check manyToMany relations if (!referencedTableName) { const manyToManyRel = table.relations.manyToMany.find( - (rel) => rel.fieldName === relationField + (rel) => rel.fieldName === relationField, ); if (manyToManyRel) { referencedTableName = manyToManyRel.rightTable; diff --git a/graphql/codegen/src/index.ts b/graphql/codegen/src/index.ts index 19ae82473..d7b71d1b1 100644 --- a/graphql/codegen/src/index.ts +++ b/graphql/codegen/src/index.ts @@ -22,22 +22,35 @@ export * from './client'; export { defineConfig } from './types/config'; // Main generate function (orchestrates the entire pipeline) -export { generate } from './core/generate'; export type { GenerateOptions, GenerateResult } from './core/generate'; +export { generate } from './core/generate'; // Config utilities export { findConfigFile, loadConfigFile } from './core/config'; // CLI shared utilities (for packages/cli to import) -export { codegenQuestions, splitCommas, printResult, camelizeArgv } from './cli/shared'; export type { CodegenAnswers } from './cli/shared'; +export { + buildDbConfig, + buildGenerateOptions, + camelizeArgv, + codegenQuestions, + filterDefined, + flattenDbFields, + hasResolvedCodegenSource, + hyphenateKeys, + normalizeCodegenListOptions, + printResult, + seedArgvFromConfig, + splitCommas, +} from './cli/shared'; // Database schema utilities (re-exported from core for convenience) -export { - buildSchemaFromDatabase, - buildSchemaSDLFromDatabase, -} from './core/database'; export type { BuildSchemaFromDatabaseOptions, BuildSchemaFromDatabaseResult, } from './core/database'; +export { + buildSchemaFromDatabase, + buildSchemaSDLFromDatabase, +} from './core/database'; diff --git a/graphql/codegen/src/types/config.ts b/graphql/codegen/src/types/config.ts index bae0a864f..91cc9fd2d 100644 --- a/graphql/codegen/src/types/config.ts +++ b/graphql/codegen/src/types/config.ts @@ -240,8 +240,6 @@ export interface GraphQLSDKConfigTarget { * Code generation options */ codegen?: { - /** Max depth for nested object field selection (default: 2) */ - maxFieldDepth?: number; /** Skip 'query' field on mutation payloads (default: true) */ skipQueryField?: boolean; }; @@ -261,15 +259,6 @@ export interface GraphQLSDKConfigTarget { */ reactQuery?: boolean; - /** - * Generate browser-compatible code using native fetch - * When true (default), uses native W3C fetch API (works in browsers and Node.js) - * When false, uses undici fetch with dispatcher support for localhost DNS resolution - * (Node.js only - enables proper *.localhost subdomain resolution on macOS) - * @default true - */ - browserCompatible?: boolean; - /** * Query key generation configuration * Controls how query keys are structured for cache management @@ -402,17 +391,14 @@ export const DEFAULT_CONFIG: GraphQLSDKConfigTarget = { schema: 'public', }, codegen: { - maxFieldDepth: 2, skipQueryField: true, }, orm: false, reactQuery: false, - browserCompatible: true, queryKeys: DEFAULT_QUERY_KEY_CONFIG, watch: DEFAULT_WATCH_CONFIG, }; - /** * Helper function to define configuration with type checking */ @@ -427,7 +413,7 @@ export function defineConfig(config: GraphQLSDKConfig): GraphQLSDKConfig { */ export function mergeConfig( base: GraphQLSDKConfigTarget, - overrides: GraphQLSDKConfigTarget + overrides: GraphQLSDKConfigTarget, ): GraphQLSDKConfigTarget { return deepmerge(base, overrides, { arrayMerge: replaceArrays }); } @@ -437,7 +423,7 @@ export function mergeConfig( * Similar to getEnvOptions pattern from @pgpmjs/env. */ export function getConfigOptions( - overrides: GraphQLSDKConfigTarget = {} + overrides: GraphQLSDKConfigTarget = {}, ): GraphQLSDKConfigTarget { return deepmerge(DEFAULT_CONFIG, overrides, { arrayMerge: replaceArrays }); } diff --git a/graphql/codegen/src/types/index.ts b/graphql/codegen/src/types/index.ts index 8e23aad73..35dbbbfc6 100644 --- a/graphql/codegen/src/types/index.ts +++ b/graphql/codegen/src/types/index.ts @@ -4,59 +4,55 @@ // Schema types export type { - CleanTable, + CleanBelongsToRelation, CleanField, CleanFieldType, - CleanRelations, - CleanBelongsToRelation, - CleanHasOneRelation, CleanHasManyRelation, + CleanHasOneRelation, CleanManyToManyRelation, - TableInflection, - TableQueryNames, - TableConstraints, + CleanRelations, + CleanTable, ConstraintInfo, ForeignKeyConstraint, + TableConstraints, + TableInflection, + TableQueryNames, } from './schema'; // Query types export type { - PageInfo, ConnectionResult, - QueryOptions, - OrderByItem, - FilterOperator, FieldFilter, - RelationalFilter, Filter, + FilterOperator, + OrderByItem, + PageInfo, + QueryOptions, + RelationalFilter, } from './query'; // Mutation types export type { - MutationOptions, CreateInput, - UpdateInput, DeleteInput, + MutationOptions, MutationResult, + UpdateInput, } from './mutation'; // Selection types export type { - SimpleFieldSelection, - FieldSelectionPreset, FieldSelection, + FieldSelectionPreset, SelectionOptions, + SimpleFieldSelection, } from './selection'; // Config types -export type { - GraphQLSDKConfig, - GraphQLSDKConfigTarget, -} from './config'; - +export type { GraphQLSDKConfig, GraphQLSDKConfigTarget } from './config'; export { + DEFAULT_CONFIG, defineConfig, getConfigOptions, mergeConfig, - DEFAULT_CONFIG, } from './config'; diff --git a/graphql/codegen/src/types/introspection.ts b/graphql/codegen/src/types/introspection.ts index e68d581e8..9642f06f9 100644 --- a/graphql/codegen/src/types/introspection.ts +++ b/graphql/codegen/src/types/introspection.ts @@ -1,6 +1,6 @@ /** * GraphQL Introspection Types - * + * * Standard types for GraphQL schema introspection via __schema query. * These mirror the GraphQL introspection spec. */ @@ -159,7 +159,9 @@ export function isNamedType(kind: IntrospectionTypeKind): boolean { /** * Unwrap a type reference to get the base named type */ -export function unwrapType(typeRef: IntrospectionTypeRef): IntrospectionTypeRef { +export function unwrapType( + typeRef: IntrospectionTypeRef, +): IntrospectionTypeRef { let current = typeRef; while (current.ofType) { current = current.ofType; diff --git a/graphql/env/package.json b/graphql/env/package.json index 025dfec10..74f4d53d2 100644 --- a/graphql/env/package.json +++ b/graphql/env/package.json @@ -42,6 +42,6 @@ "postgraphile" ], "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/graphql/explorer/package.json b/graphql/explorer/package.json index f6f7e9e84..fe8c613e3 100644 --- a/graphql/explorer/package.json +++ b/graphql/explorer/package.json @@ -54,7 +54,7 @@ "devDependencies": { "@types/express": "^5.0.6", "@types/graphql-upload": "^8.0.12", - "makage": "^0.1.10", + "makage": "^0.1.12", "nodemon": "^3.1.10", "ts-node": "^10.9.2" }, diff --git a/graphql/gql-ast/package.json b/graphql/gql-ast/package.json index 9193de04b..6c6ba7791 100644 --- a/graphql/gql-ast/package.json +++ b/graphql/gql-ast/package.json @@ -39,6 +39,6 @@ "schema" ], "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/graphql/playwright-test/package.json b/graphql/playwright-test/package.json index ba473b4fa..f3d6aabd4 100644 --- a/graphql/playwright-test/package.json +++ b/graphql/playwright-test/package.json @@ -32,7 +32,7 @@ "@playwright/test": "^1.57.0", "@types/express": "^5.0.6", "@types/pg": "^8.16.0", - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@constructive-io/graphql-env": "workspace:^", diff --git a/graphql/query/package.json b/graphql/query/package.json index 435625cb6..332f6b04b 100644 --- a/graphql/query/package.json +++ b/graphql/query/package.json @@ -42,6 +42,6 @@ "database" ], "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/graphql/react/package.json b/graphql/react/package.json index 325948cca..eae70c3c1 100644 --- a/graphql/react/package.json +++ b/graphql/react/package.json @@ -38,6 +38,6 @@ "@testing-library/jest-dom": "5.11.10", "@testing-library/react": "11.2.5", "@types/react": "^19.2.8", - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/graphql/server-test/package.json b/graphql/server-test/package.json index 3e5277e82..0a430b3ae 100644 --- a/graphql/server-test/package.json +++ b/graphql/server-test/package.json @@ -32,7 +32,7 @@ "@types/express": "^5.0.6", "@types/pg": "^8.16.0", "@types/supertest": "^6.0.2", - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@constructive-io/graphql-env": "workspace:^", diff --git a/graphql/server/package.json b/graphql/server/package.json index 64561cf16..feb31ef70 100644 --- a/graphql/server/package.json +++ b/graphql/server/package.json @@ -84,7 +84,7 @@ "@types/pg": "^8.16.0", "@types/request-ip": "^0.0.41", "graphile-test": "workspace:*", - "makage": "^0.1.10", + "makage": "^0.1.12", "nodemon": "^3.1.10", "rimraf": "^6.1.2", "ts-node": "^10.9.2" diff --git a/graphql/test-app/.gitignore b/graphql/test-app/.gitignore new file mode 100644 index 000000000..a39b67259 --- /dev/null +++ b/graphql/test-app/.gitignore @@ -0,0 +1 @@ +src/generated/* \ No newline at end of file diff --git a/graphql/test-app/README.md b/graphql/test-app/README.md new file mode 100644 index 000000000..fbb152e9d --- /dev/null +++ b/graphql/test-app/README.md @@ -0,0 +1,62 @@ +# test-codegen-app + +Local integration app for validating `@constructive-io/graphql-codegen` output against a real GraphQL endpoint. + +This package is intended for: +- Generating React Query + ORM output from the current workspace codegen implementation. +- Type-checking real generated artifacts. +- Running live integration checks with real auth credentials. + +This package is not part of CI test gating and is meant for local/manual verification. + +## What It Tests + +- React Query output mode generation and usage. +- ORM output mode generation and usage. +- Generated type fidelity in real app code (`tsc --noEmit`). +- Live endpoint behavior in `tests/*.test.ts`. + +## Local Usage + +Run from repo root. + +1. Generate from `codegen.config.ts`: + +```bash +pnpm --filter @constructive-io/test-codegen-app codegen +``` + +2. Type-check generated output: + +```bash +pnpm --filter @constructive-io/test-codegen-app typecheck +``` + +3. Build the app: + +```bash +pnpm --filter @constructive-io/test-codegen-app build +``` + +4. Run integration tests (non-live mode, skips credentialed tests): + +```bash +pnpm --filter @constructive-io/test-codegen-app test:integration +``` + +5. Run live integration tests: + +```bash +GRAPHQL_TEST_EMAIL="you@example.com" \ +GRAPHQL_TEST_PASSWORD="your-password" \ +pnpm --filter @constructive-io/test-codegen-app test:integration:live +``` + +Optional: +- `GRAPHQL_TEST_ENDPOINT` to override the default endpoint used by live tests. + +## Notes + +- `codegen` uses `graphql/test-app/codegen.config.ts` (currently pointed at the production endpoint for validation). +- `codegen:orm` is available for direct endpoint-driven ORM generation checks. +- Keep this app focused on realistic generated-API usage and regression coverage for codegen refactors. diff --git a/graphql/test-app/codegen.config.ts b/graphql/test-app/codegen.config.ts new file mode 100644 index 000000000..a54b824d1 --- /dev/null +++ b/graphql/test-app/codegen.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from '@constructive-io/graphql-codegen'; + +const config = defineConfig({ + endpoint: 'http://api.localhost:3000/graphql', + output: 'src/generated', + reactQuery: true, +}); + +export default config; diff --git a/graphql/test-app/index.html b/graphql/test-app/index.html new file mode 100644 index 000000000..43074d8dc --- /dev/null +++ b/graphql/test-app/index.html @@ -0,0 +1,12 @@ + + + + + + GraphQL Codegen Test App + + +
+ + + diff --git a/graphql/test-app/package.json b/graphql/test-app/package.json new file mode 100644 index 000000000..a1a3619f5 --- /dev/null +++ b/graphql/test-app/package.json @@ -0,0 +1,39 @@ +{ + "name": "@constructive-io/test-codegen-app", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build:app": "tsc -b && vite build", + "preview": "vite preview", + "codegen": "tsx ../codegen/src/cli/index.ts --config codegen.config.ts", + "codegen:orm": "tsx ../codegen/src/cli/index.ts --endpoint http://api.localhost:3000/graphql --output src/generated --orm", + "typecheck": "tsc --noEmit", + "test:types": "tsc --noEmit", + "test:integration": "node --import tsx --test \"tests/**/*.test.ts\"", + "test:integration:live": "GRAPHQL_TEST_LIVE_REQUIRED=1 node --import tsx --test \"tests/**/*.test.ts\"", + "analyze": "tsx scripts/analyze-bundle.ts", + "analyze:visual": "vite build && echo '\nBundle report: dist/bundle-stats.html'" + }, + "dependencies": { + "@0no-co/graphql.web": "^1.2.0", + "@constructive-io/graphql-types": "workspace:^", + "@tanstack/react-query": "^5.90.20", + "gql-ast": "workspace:^", + "graphql": "15.10.1", + "react": "^19.2.3", + "react-dom": "^19.2.3" + }, + "devDependencies": { + "@constructive-io/graphql-codegen": "workspace:^", + "@types/react": "^19.2.13", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^4.5.2", + "react-test-renderer": "^19.2.3", + "rollup-plugin-visualizer": "^6.0.5", + "tsx": "^4.20.3", + "typescript": "^5.8.3", + "vite": "^6.3.5" + } +} diff --git a/graphql/test-app/scripts/analyze-bundle.ts b/graphql/test-app/scripts/analyze-bundle.ts new file mode 100644 index 000000000..7db8f509e --- /dev/null +++ b/graphql/test-app/scripts/analyze-bundle.ts @@ -0,0 +1,155 @@ +/** + * Bundle size analysis script + * + * Builds the app with Rollup's generateBundle hook to capture per-module sizes, + * then groups them by category (generated hooks, ORM, vendor libs, app code). + * + * Usage: tsx scripts/analyze-bundle.ts + */ +import { build } from 'vite'; +import react from '@vitejs/plugin-react'; +import { gzipSync, brotliCompressSync } from 'node:zlib'; + +interface ModuleInfo { + originalLength: number; + renderedLength: number; + removedExports: string[]; + code: string | null; +} + +interface ChunkInfo { + name: string; + size: number; + gzip: number; + brotli: number; + modules: Record; +} + +const chunks: ChunkInfo[] = []; + +const result = await build({ + configFile: false, + plugins: [ + react(), + { + name: 'capture-bundle-stats', + generateBundle(_options, bundle) { + for (const [fileName, chunk] of Object.entries(bundle)) { + if (chunk.type !== 'chunk') continue; + const code = Buffer.from(chunk.code); + chunks.push({ + name: fileName, + size: code.length, + gzip: gzipSync(code).length, + brotli: brotliCompressSync(code).length, + modules: chunk.modules as Record, + }); + } + }, + }, + ], + build: { + write: false, + minify: 'esbuild', + }, + logLevel: 'silent', +}); + +// Categorize modules +interface Category { + label: string; + test: (id: string) => boolean; +} + +const categories: Category[] = [ + { label: 'Generated Hooks', test: (id) => id.includes('generated/hooks') }, + { label: 'Generated ORM', test: (id) => id.includes('generated/orm') }, + { label: 'Generated Types', test: (id) => id.includes('generated/') && (id.includes('types.ts') || id.includes('schema-types')) }, + { label: 'React', test: (id) => /node_modules\/(react|react-dom|scheduler)\//.test(id) }, + { label: 'React Query', test: (id) => id.includes('@tanstack/react-query') }, + { label: 'GraphQL (graphql.web + gql-ast)', test: (id) => id.includes('@0no-co/graphql.web') || id.includes('gql-ast') }, + { label: 'GraphQL (graphql 15)', test: (id) => id.includes('node_modules/graphql') }, + { label: 'App Code', test: (id) => !id.includes('node_modules') && !id.includes('generated/') }, +]; + +const catSizes: Record = {}; +let uncategorized = 0; + +for (const chunk of chunks) { + for (const [moduleId, info] of Object.entries(chunk.modules)) { + let matched = false; + for (const cat of categories) { + if (cat.test(moduleId)) { + if (!catSizes[cat.label]) catSizes[cat.label] = { original: 0, rendered: 0 }; + catSizes[cat.label].original += info.originalLength; + catSizes[cat.label].rendered += info.renderedLength; + matched = true; + break; + } + } + if (!matched) { + uncategorized += info.renderedLength; + } + } +} + +// Output +console.log('\n========================================'); +console.log(' BUNDLE SIZE ANALYSIS'); +console.log('========================================\n'); + +const totalChunk = chunks[0]; +if (totalChunk) { + const fmt = (n: number) => (n / 1024).toFixed(1) + ' KB'; + console.log(`Total bundle: ${fmt(totalChunk.size)} minified | ${fmt(totalChunk.gzip)} gzip | ${fmt(totalChunk.brotli)} brotli\n`); +} + +console.log('By category (rendered/minified size in bundle):'); +console.log('─'.repeat(60)); + +const sorted = Object.entries(catSizes).sort((a, b) => b[1].rendered - a[1].rendered); +const totalRendered = sorted.reduce((sum, [, v]) => sum + v.rendered, 0) + uncategorized; + +for (const [label, { original, rendered }] of sorted) { + const pct = ((rendered / totalRendered) * 100).toFixed(1); + const pad = label.padEnd(35); + const renderedKB = (rendered / 1024).toFixed(1).padStart(8); + const originalKB = (original / 1024).toFixed(1).padStart(8); + console.log(` ${pad} ${renderedKB} KB (${pct.padStart(5)}%) source: ${originalKB} KB`); +} + +if (uncategorized > 0) { + const pct = ((uncategorized / totalRendered) * 100).toFixed(1); + console.log(` ${'Other'.padEnd(35)} ${(uncategorized / 1024).toFixed(1).padStart(8)} KB (${pct.padStart(5)}%)`); +} + +console.log('─'.repeat(60)); +console.log(` ${'TOTAL'.padEnd(35)} ${(totalRendered / 1024).toFixed(1).padStart(8)} KB\n`); + +// Tree-shaking effectiveness +const hooksSource = catSizes['Generated Hooks']; +const ormSource = catSizes['Generated ORM']; +if (hooksSource || ormSource) { + console.log('Tree-shaking effectiveness:'); + console.log('─'.repeat(60)); + if (hooksSource) { + const ratio = ((1 - hooksSource.rendered / hooksSource.original) * 100).toFixed(1); + console.log(` Hooks: ${(hooksSource.original / 1024).toFixed(0)} KB source → ${(hooksSource.rendered / 1024).toFixed(1)} KB in bundle (${ratio}% eliminated)`); + } + if (ormSource) { + const ratio = ((1 - ormSource.rendered / ormSource.original) * 100).toFixed(1); + console.log(` ORM: ${(ormSource.original / 1024).toFixed(0)} KB source → ${(ormSource.rendered / 1024).toFixed(1)} KB in bundle (${ratio}% eliminated)`); + } + console.log(''); +} + +// Module count +let totalModules = 0; +let generatedModules = 0; +for (const chunk of chunks) { + for (const moduleId of Object.keys(chunk.modules)) { + totalModules++; + if (moduleId.includes('generated/')) generatedModules++; + } +} +console.log(`Modules: ${totalModules} total, ${generatedModules} generated (${(totalModules - generatedModules)} vendor/app)\n`); diff --git a/graphql/test-app/src/App.tsx b/graphql/test-app/src/App.tsx new file mode 100644 index 000000000..14e947184 --- /dev/null +++ b/graphql/test-app/src/App.tsx @@ -0,0 +1,1039 @@ +/** + * Test App for graphql-codegen hooks + * + * Tests the full auth flow (signUp, signIn, signOut) and then + * exercises authenticated queries/mutations with type-safe select. + * + * Run `pnpm codegen` first to generate the hooks from the live API. + */ + +import { useState, FormEvent } from 'react'; +import { useQueryClient } from '@tanstack/react-query'; + +import { + // Client configuration + configure, + + // Auth mutation hooks + useSignUpMutation, + useSignInMutation, + useSignOutMutation, + + // Authenticated query hooks + useCurrentUserQuery, + useCurrentUserIdQuery, + useUsersQuery, + useDatabasesQuery, + useDatabaseQuery, + useSchemasQuery, + useApisQuery, + useDomainsQuery, + + // Authenticated mutation hooks — Users + useCreateUserMutation, + useUpdateUserMutation, + + // Authenticated mutation hooks — Databases + useCreateDatabaseMutation, + useUpdateDatabaseMutation, + useDeleteDatabaseMutation, + + // Authenticated mutation hooks — Schemas, APIs, Sites, Domains + useCreateSchemaMutation, + useCreateApiMutation, + useCreateSiteMutation, + useCreateDomainMutation, +} from './generated/hooks'; + +const ENDPOINT = 'http://api.localhost:3000/graphql'; + +// --------------------------------------------------------------------------- +// Auth helpers +// --------------------------------------------------------------------------- + +function reconfigureClient(token?: string) { + configure({ + endpoint: ENDPOINT, + headers: token ? { Authorization: `Bearer ${token}` } : {}, + }); +} + +// --------------------------------------------------------------------------- +// Sign Up Form +// --------------------------------------------------------------------------- +function SignUpForm({ onAuth }: { onAuth: (token: string, userId: string) => void }) { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + + const { mutate, isPending, error } = useSignUpMutation({ + selection: { + fields: { + result: { + select: { + accessToken: true, + userId: true, + isVerified: true, + }, + }, + }, + }, + }); + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + mutate( + { input: { email, password } }, + { + onSuccess: (data) => { + const result = data.signUp.result; + if (result?.accessToken) { + onAuth(result.accessToken, result.userId ?? ''); + } + }, + }, + ); + }; + + return ( +
+

Sign Up

+ setEmail(e.target.value)} required style={inputStyle} /> + setPassword(e.target.value)} required style={inputStyle} /> + + {error &&

{error.message}

} +
+ ); +} + +// --------------------------------------------------------------------------- +// Sign In Form +// --------------------------------------------------------------------------- +function SignInForm({ onAuth }: { onAuth: (token: string, userId: string) => void }) { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + + const { mutate, isPending, error } = useSignInMutation({ + selection: { + fields: { + result: { + select: { + accessToken: true, + userId: true, + isVerified: true, + totpEnabled: true, + }, + }, + }, + }, + }); + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + mutate( + { input: { email, password } }, + { + onSuccess: (data) => { + // AUTOCOMPLETION TEST: type `data.signIn.result.` — should suggest accessToken, userId, isVerified, totpEnabled + const result = data.signIn.result; + if (result?.accessToken) { + onAuth(result.accessToken, result.userId ?? ''); + } + }, + }, + ); + }; + + return ( +
+

Sign In

+ setEmail(e.target.value)} required style={inputStyle} /> + setPassword(e.target.value)} required style={inputStyle} /> + + {error &&

{error.message}

} +
+ ); +} + +// --------------------------------------------------------------------------- +// Auth Page (unauthenticated) +// --------------------------------------------------------------------------- +function AuthPage({ onAuth }: { onAuth: (token: string, userId: string) => void }) { + const [mode, setMode] = useState<'signin' | 'signup'>('signin'); + + return ( +
+
+ + +
+ {mode === 'signin' ? : } +
+ ); +} + +// =========================================================================== +// SECTION: Identity & Profile +// =========================================================================== + +function CurrentUser() { + const { data, isLoading, error } = useCurrentUserQuery({ + selection: { fields: { id: true, username: true, displayName: true, createdAt: true } }, + }); + + if (isLoading) return

Loading current user...

; + if (error) return

Error: {error.message}

; + + // AUTOCOMPLETION TEST: type `data?.currentUser.` — should suggest id, username, displayName, createdAt + const user = data?.currentUser; + + return ( +
+

Current User

+ {user ? ( +
+
ID
{user.id}
+
Username
{user.username ?? '—'}
+
Display Name
{user.displayName ?? '—'}
+
Created At
{user.createdAt}
+
+ ) : ( +

No user found

+ )} +
+ ); +} + +function CurrentUserId() { + const { data, isLoading } = useCurrentUserIdQuery(); + if (isLoading) return

Loading...

; + + return ( +
+

Current User ID (scalar)

+ {data?.currentUserId ?? 'null'} +
+ ); +} + +function UserList() { + const { data, isLoading, error } = useUsersQuery({ + selection: { + fields: { id: true, username: true, displayName: true, createdAt: true }, + first: 10, + orderBy: ['CREATED_AT_DESC'], + }, + }); + + if (isLoading) return

Loading users...

; + if (error) return

Error: {error.message}

; + + const users = data?.users?.nodes ?? []; + + return ( +
+

Users ({users.length})

+ [user.username, user.displayName, user.createdAt]} + /> +
+ ); +} + +function CreateUserForm() { + const [username, setUsername] = useState(''); + const [displayName, setDisplayName] = useState(''); + const { mutate, isPending, error, data: result } = useCreateUserMutation({ + selection: { fields: { id: true, username: true, displayName: true } }, + }); + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + mutate({ username, displayName }); + }; + + return ( +
+

Create User

+
+ setUsername(e.target.value)} required style={inputStyle} /> + setDisplayName(e.target.value)} style={inputStyle} /> + +
+ {error &&

{error.message}

} + {result &&
{JSON.stringify(result.createUser.user, null, 2)}
} +
+ ); +} + +function UpdateUserForm({ userId }: { userId: string }) { + const [displayName, setDisplayName] = useState(''); + const { mutate, isPending, error, data: result } = useUpdateUserMutation({ + selection: { fields: { id: true, username: true, displayName: true } }, + }); + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + mutate({ id: userId, patch: { displayName } }); + }; + + return ( +
+

Update Current User

+
+ setDisplayName(e.target.value)} required style={inputStyle} /> + +
+ {error &&

{error.message}

} + {result &&
{JSON.stringify(result.updateUser.user, null, 2)}
} +
+ ); +} + +// =========================================================================== +// SECTION: Database Management (full CRUD) +// =========================================================================== + +function DatabaseListWithSchemas() { + const { data, isLoading, error, refetch } = useDatabasesQuery({ + selection: { + fields: { + id: true, + name: true, + label: true, + schemaName: true, + createdAt: true, + schemas: { + first: 20, + filter: { + isPublic: { equalTo: true }, + schemaName: { startsWithInsensitive: 'app_' }, + }, + orderBy: ['SCHEMA_NAME_ASC'], + select: { + id: true, + name: true, + schemaName: true, + isPublic: true, + }, + }, + }, + first: 10, + where: { + and: [ + { name: { includesInsensitive: 'prod' } }, + { createdAt: { greaterThanOrEqualTo: '2026-01-01T00:00:00.000Z' } }, + ], + }, + orderBy: ['CREATED_AT_DESC'], + }, + }); + + if (isLoading) return

Loading databases...

; + if (error) return

Error: {error.message}

; + + // AUTOCOMPLETION TEST: type `db.` — should suggest id, name, label, createdAt, schemas + const databases = data?.databases?.nodes ?? []; + + return ( +
+
+

Databases ({databases.length})

+ +
+ {databases.length === 0 ? ( +

No databases — create one below

+ ) : ( + databases.map((db) => ( +
+
+
+ {db.name} + {db.label && ({db.label})} + {db.id.slice(0, 8)} +
+ {db.createdAt} +
+ {/* NESTED RELATION: schemas under this database */} + {db.schemas?.nodes && db.schemas.nodes.length > 0 && ( +
+ Schemas: {db.schemas.nodes.map((s) => ( + + {s.schemaName ?? s.name} + + ))} +
+ )} +
+ )) + )} +
+ ); +} + +function DatabaseDetail({ databaseId }: { databaseId: string }) { + const { data, isLoading, error } = useDatabaseQuery({ + id: databaseId, + selection: { + fields: { + id: true, + name: true, + label: true, + schemaName: true, + privateSchemaName: true, + createdAt: true, + updatedAt: true, + // NESTED: owner user + owner: { + select: { id: true, username: true, displayName: true }, + }, + }, + }, + }); + + if (isLoading) return

Loading database...

; + if (error) return

Error: {error.message}

; + + // AUTOCOMPLETION TEST: type `data?.database.` — should suggest id, name, label, owner, etc. + const db = data?.database; + if (!db) return

Database not found

; + + return ( +
+

Database Detail

+
+
ID
{db.id}
+
Name
{db.name}
+
Label
{db.label ?? '—'}
+
Public Schema
{db.schemaName ?? '—'}
+
Private Schema
{db.privateSchemaName ?? '—'}
+
Owner
{db.owner?.displayName ?? db.owner?.username ?? '—'}
+
Created
{db.createdAt}
+
Updated
{db.updatedAt}
+
+
+ ); +} + +function CreateDatabaseForm({ userId }: { userId: string }) { + const [name, setName] = useState(''); + const [label, setLabel] = useState(''); + const { mutate, isPending, error, data: result } = useCreateDatabaseMutation({ + selection: { fields: { id: true, name: true, label: true, createdAt: true } }, + }); + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + // AUTOCOMPLETION TEST: mutate arg should suggest ownerId, name, label, schemaName, etc. + mutate({ + ownerId: userId, + name: name.toLowerCase().replace(/[^a-z0-9_]/g, '_'), + label: label || null, + }); + }; + + return ( +
+

Create Database

+
+ setName(e.target.value)} required style={inputStyle} /> + setLabel(e.target.value)} style={inputStyle} /> + +
+ {error &&

{error.message}

} + {result &&
{JSON.stringify(result.createDatabase.database, null, 2)}
} +
+ ); +} + +function UpdateDatabaseForm() { + const [id, setId] = useState(''); + const [label, setLabel] = useState(''); + const { mutate, isPending, error, data: result } = useUpdateDatabaseMutation({ + selection: { fields: { id: true, name: true, label: true } }, + }); + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + // AUTOCOMPLETION TEST: patch should suggest DatabasePatch fields — ownerId, name, label, etc. + mutate({ id, patch: { label } }); + }; + + return ( +
+

Update Database

+
+ setId(e.target.value)} required style={{ ...inputStyle, fontFamily: 'monospace', fontSize: 12 }} /> + setLabel(e.target.value)} required style={inputStyle} /> + +
+ {error &&

{error.message}

} + {result &&
{JSON.stringify(result.updateDatabase.database, null, 2)}
} +
+ ); +} + +function DeleteDatabaseForm() { + const [id, setId] = useState(''); + const [confirm, setConfirm] = useState(false); + const { mutate, isPending, error, data: result } = useDeleteDatabaseMutation({ + selection: { fields: { id: true, name: true } }, + }); + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + if (!confirm) return; + mutate({ id }); + }; + + return ( +
+

Delete Database

+
+ { setId(e.target.value); setConfirm(false); }} required style={{ ...inputStyle, fontFamily: 'monospace', fontSize: 12 }} /> + + +
+ {error &&

{error.message}

} + {result &&
Deleted: {JSON.stringify(result.deleteDatabase.database, null, 2)}
} +
+ ); +} + +// =========================================================================== +// SECTION: Schema & API Management +// =========================================================================== + +function SchemaList() { + const { data, isLoading, error } = useSchemasQuery({ + selection: { + fields: { + id: true, + name: true, + schemaName: true, + isPublic: true, + // NESTED RELATION: parent database + database: { + select: { id: true, name: true }, + }, + }, + first: 20, + }, + }); + + if (isLoading) return

Loading schemas...

; + if (error) return

Error: {error.message}

; + + const schemas = data?.schemas?.nodes ?? []; + + return ( +
+

Schemas ({schemas.length})

+ [ + s.schemaName, + s.name, + s.database?.name ?? '—', + s.isPublic ? 'Yes' : 'No', + ]} + /> +
+ ); +} + +function CreateSchemaForm() { + const [databaseId, setDatabaseId] = useState(''); + const [name, setName] = useState(''); + const [schemaName, setSchemaName] = useState(''); + const { mutate, isPending, error, data: result } = useCreateSchemaMutation({ + selection: { fields: { id: true, name: true, schemaName: true, isPublic: true } }, + }); + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + // AUTOCOMPLETION TEST: mutate arg should suggest databaseId, name, schemaName, label, isPublic, etc. + mutate({ + databaseId, + name, + schemaName: schemaName.toLowerCase().replace(/[^a-z0-9_]/g, '_'), + }); + }; + + return ( +
+

Create Schema

+
+ setDatabaseId(e.target.value)} required style={{ ...inputStyle, fontFamily: 'monospace', fontSize: 12 }} /> + setName(e.target.value)} required style={inputStyle} /> + setSchemaName(e.target.value)} required style={inputStyle} /> + +
+ {error &&

{error.message}

} + {result &&
{JSON.stringify(result.createSchema.schema, null, 2)}
} +
+ ); +} + +function ApiList() { + const { data, isLoading, error } = useApisQuery({ + selection: { + fields: { + id: true, + name: true, + dbname: true, + roleName: true, + anonRole: true, + isPublic: true, + // NESTED RELATION: parent database + database: { + select: { id: true, name: true }, + }, + }, + first: 20, + }, + }); + + if (isLoading) return

Loading APIs...

; + if (error) return

Error: {error.message}

; + + const apis = data?.apis?.nodes ?? []; + + return ( +
+

APIs ({apis.length})

+ [ + api.name, + api.dbname, + api.roleName, + api.database?.name ?? '—', + api.isPublic ? 'Yes' : 'No', + ]} + /> +
+ ); +} + +function CreateApiForm() { + const [databaseId, setDatabaseId] = useState(''); + const [name, setName] = useState(''); + const { mutate, isPending, error, data: result } = useCreateApiMutation({ + selection: { fields: { id: true, name: true, dbname: true, roleName: true, anonRole: true, isPublic: true } }, + }); + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + // AUTOCOMPLETION TEST: mutate arg should suggest databaseId, name, dbname, roleName, anonRole, isPublic + mutate({ databaseId, name }); + }; + + return ( +
+

Create API

+
+ setDatabaseId(e.target.value)} required style={{ ...inputStyle, fontFamily: 'monospace', fontSize: 12 }} /> + setName(e.target.value)} required style={inputStyle} /> + +
+ {error &&

{error.message}

} + {result &&
{JSON.stringify(result.createApi.api, null, 2)}
} +
+ ); +} + +// =========================================================================== +// SECTION: Site & Domain Management +// =========================================================================== + +function CreateSiteForm() { + const [databaseId, setDatabaseId] = useState(''); + const [title, setTitle] = useState(''); + const [description, setDescription] = useState(''); + const { mutate, isPending, error, data: result } = useCreateSiteMutation({ + selection: { fields: { id: true, title: true, description: true, dbname: true } }, + }); + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + // AUTOCOMPLETION TEST: mutate arg should suggest databaseId, title, description, favicon, ogImage, etc. + mutate({ databaseId, title, description: description || null }); + }; + + return ( +
+

Create Site

+
+ setDatabaseId(e.target.value)} required style={{ ...inputStyle, fontFamily: 'monospace', fontSize: 12 }} /> + setTitle(e.target.value)} required style={inputStyle} /> + setDescription(e.target.value)} style={inputStyle} /> + +
+ {error &&

{error.message}

} + {result &&
{JSON.stringify(result.createSite.site, null, 2)}
} +
+ ); +} + +function DomainList() { + const { data, isLoading, error } = useDomainsQuery({ + selection: { + fields: { + id: true, + subdomain: true, + domain: true, + // NESTED RELATIONS: api and site via FK + api: { select: { id: true, name: true } }, + site: { select: { id: true, title: true } }, + }, + first: 20, + }, + }); + + if (isLoading) return

Loading domains...

; + if (error) return

Error: {error.message}

; + + // AUTOCOMPLETION TEST: type `d.` — should suggest id, subdomain, domain, api, site + const domains = data?.domains?.nodes ?? []; + + return ( +
+

Domains ({domains.length})

+ [ + d.subdomain ?? '—', + d.domain ?? '—', + d.api?.name ?? '—', + d.site?.title ?? '—', + ]} + /> +
+ ); +} + +function CreateDomainForm() { + const [databaseId, setDatabaseId] = useState(''); + const [apiId, setApiId] = useState(''); + const [siteId, setSiteId] = useState(''); + const [subdomain, setSubdomain] = useState(''); + const [domain, setDomain] = useState(''); + const { mutate, isPending, error, data: result } = useCreateDomainMutation({ + selection: { fields: { id: true, subdomain: true, domain: true } }, + }); + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + // AUTOCOMPLETION TEST: mutate arg should suggest databaseId, apiId, siteId, subdomain, domain + mutate({ databaseId, apiId, siteId, subdomain, domain }); + }; + + return ( +
+

Create Domain

+
+
+ setDatabaseId(e.target.value)} required style={{ ...inputStyle, fontFamily: 'monospace', fontSize: 12 }} /> + setApiId(e.target.value)} required style={{ ...inputStyle, fontFamily: 'monospace', fontSize: 12 }} /> + setSiteId(e.target.value)} required style={{ ...inputStyle, fontFamily: 'monospace', fontSize: 12 }} /> +
+
+ setSubdomain(e.target.value)} style={inputStyle} /> + setDomain(e.target.value)} style={inputStyle} /> + +
+
+ {error &&

{error.message}

} + {result &&
{JSON.stringify(result.createDomain.domain, null, 2)}
} +
+ ); +} + +// =========================================================================== +// Shared: Generic data table component +// =========================================================================== + +function DataTable({ + columns, + rows, + renderRow, +}: { + columns: string[]; + rows: T[]; + renderRow: (row: T) => (string | boolean | null | undefined)[]; +}) { + if (rows.length === 0) return

None

; + + return ( + + + + {columns.map((col) => ( + + ))} + + + + {rows.map((row) => ( + + {renderRow(row).map((cell, i) => ( + + ))} + + ))} + +
{col}
{cell ?? '—'}
+ ); +} + +// =========================================================================== +// Authenticated Dashboard +// =========================================================================== + +function Dashboard({ token, userId, onSignOut }: { token: string; userId: string; onSignOut: () => void }) { + const queryClient = useQueryClient(); + const [activeDbId, setActiveDbId] = useState(null); + + const { mutate: signOut, isPending: signingOut } = useSignOutMutation({ + selection: { + fields: { + clientMutationId: true, + }, + }, + onSuccess: () => { + queryClient.clear(); + onSignOut(); + }, + }); + + return ( +
+ {/* Header */} +
+
+ Authenticated + {token.slice(0, 20)}... +
+ +
+ + {/* Identity & Profile */} + + + + + {/* Users */} + + + + + + {/* Database Management */} + + + + + + + {/* Database Detail (enter an ID to inspect) */} +
+

Inspect Database (findOne)

+
+ setActiveDbId(e.target.value || null)} + style={{ ...inputStyle, fontFamily: 'monospace', fontSize: 12, flex: 1 }} + /> +
+
+ {activeDbId && } + + {/* Schemas & APIs */} + + + + + + + {/* Sites & Domains */} + + + + +
+ ); +} + +function SectionHeader({ title }: { title: string }) { + return ( +

+ {title} +

+ ); +} + +// =========================================================================== +// Main App +// =========================================================================== + +export default function App() { + const [auth, setAuth] = useState<{ token: string; userId: string } | null>(null); + const queryClient = useQueryClient(); + + const handleAuth = (token: string, userId: string) => { + reconfigureClient(token); + queryClient.clear(); + setAuth({ token, userId }); + }; + + const handleSignOut = () => { + reconfigureClient(); + setAuth(null); + }; + + return ( +
+

GraphQL Codegen Test App

+

+ Auth flow + CRUD mutations + nested relation queries with type-safe select. + Open src/App.tsx in your editor to inspect types. +

+ + {auth ? ( + + ) : ( + + )} +
+ ); +} + +// =========================================================================== +// Styles +// =========================================================================== + +const formStyle: React.CSSProperties = { + display: 'flex', + flexDirection: 'column', + gap: 10, + maxWidth: 360, +}; + +const rowForm: React.CSSProperties = { + display: 'flex', + gap: 8, + alignItems: 'flex-end', + flexWrap: 'wrap', +}; + +const inputStyle: React.CSSProperties = { + padding: '8px 12px', + border: '1px solid #d1d5db', + borderRadius: 6, + fontSize: 14, +}; + +const btnStyle: React.CSSProperties = { + padding: '8px 16px', + background: '#2563eb', + color: '#fff', + border: 'none', + borderRadius: 6, + fontSize: 14, + cursor: 'pointer', + whiteSpace: 'nowrap', +}; + +const btnSmall: React.CSSProperties = { + padding: '4px 10px', + color: '#fff', + border: 'none', + borderRadius: 4, + fontSize: 12, + cursor: 'pointer', +}; + +const tabStyle: React.CSSProperties = { + padding: '6px 16px', + background: 'none', + border: '1px solid #d1d5db', + borderRadius: 6, + fontSize: 14, + cursor: 'pointer', +}; + +const errStyle: React.CSSProperties = { + color: '#dc2626', + fontSize: 13, + marginTop: 4, +}; + +const cardStyle: React.CSSProperties = { + border: '1px solid #e5e7eb', + borderRadius: 8, + padding: 16, + marginBottom: 16, +}; + +const dlStyle: React.CSSProperties = { + display: 'grid', + gridTemplateColumns: 'auto 1fr', + gap: '4px 16px', + margin: 0, + fontSize: 14, +}; + +const tableStyle: React.CSSProperties = { + width: '100%', + borderCollapse: 'collapse', + fontSize: 14, +}; + +const thStyle: React.CSSProperties = { + textAlign: 'left', + borderBottom: '2px solid #e5e7eb', + padding: '6px 8px', +}; + +const tdStyle: React.CSSProperties = { + borderBottom: '1px solid #f3f4f6', + padding: '6px 8px', +}; + +const preStyle: React.CSSProperties = { + background: '#f9fafb', + padding: 12, + borderRadius: 6, + fontSize: 12, + overflow: 'auto', + marginTop: 8, +}; + +const badge: React.CSSProperties = { + display: 'inline-block', + padding: '2px 8px', + borderRadius: 4, + fontSize: 12, + marginRight: 4, +}; diff --git a/graphql/test-app/src/main.tsx b/graphql/test-app/src/main.tsx new file mode 100644 index 000000000..040b1e09f --- /dev/null +++ b/graphql/test-app/src/main.tsx @@ -0,0 +1,28 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; + +import { configure } from './generated/hooks'; +import App from './App.tsx'; + +// Configure the generated SDK client (no auth initially — App manages JWT) +configure({ + endpoint: 'http://api.localhost:3000/graphql', +}); + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: false, + refetchOnWindowFocus: false, + }, + }, +}); + +createRoot(document.getElementById('root')!).render( + + + + + , +); diff --git a/graphql/test-app/src/type-tests/react-query-helpers-options.type-test.ts b/graphql/test-app/src/type-tests/react-query-helpers-options.type-test.ts new file mode 100644 index 000000000..005cb8e0d --- /dev/null +++ b/graphql/test-app/src/type-tests/react-query-helpers-options.type-test.ts @@ -0,0 +1,291 @@ +/** + * Compile-time regression checks for helper overloads and React Query options. + * + * Focus: + * - fetch/prefetch signatures for selection-enabled queries + * - optional variables flow for non-selection custom queries + * - pass-through and blocked React Query options + */ + +import { QueryClient } from '@tanstack/react-query'; + +import { + fetchDatabasesQuery, + fetchStepsRequiredQuery, + fetchUserByUsernameQuery, + prefetchDatabasesQuery, + prefetchStepsRequiredQuery, + prefetchUserByUsernameQuery, + useCurrentUserQuery, + useDatabasesQuery, + useSignInMutation, + useStepsRequiredQuery, + useUserByUsernameQuery, +} from '../generated/hooks'; + +type Assert = T; +type HasKey = K extends keyof T ? true : false; +type NotHasKey = K extends keyof T ? false : true; + +function helperOverloadChecks() { + const queryClient = new QueryClient(); + + const idOnlyDatabasesFetch = fetchDatabasesQuery({ + selection: { + first: 2, + fields: { + id: true, + }, + }, + }); + type IdOnlyDatabaseNode = Awaited< + typeof idOnlyDatabasesFetch + >['databases']['nodes'][number]; + type _idOnlyDatabaseFetchOmitsName = Assert< + NotHasKey + >; + + const selectedDatabasesFetch = fetchDatabasesQuery({ + selection: { + first: 2, + fields: { + id: true, + name: true, + schemas: { + first: 1, + select: { + id: true, + schemaName: true, + }, + }, + }, + }, + }); + type SelectedDatabaseNode = Awaited< + typeof selectedDatabasesFetch + >['databases']['nodes'][number]; + type _selectedDatabaseFetchHasName = Assert< + HasKey + >; + + prefetchDatabasesQuery(queryClient, { + selection: { + first: 2, + fields: { + id: true, + }, + }, + }); + + // @ts-expect-error selection.fields is required + fetchDatabasesQuery({ selection: { first: 2 } }); + + const selectedUserByUsernameFetch = fetchUserByUsernameQuery({ + variables: { username: 'dev' }, + selection: { + fields: { + id: true, + username: true, + }, + }, + }); + type SelectedUserByUsername = Awaited< + typeof selectedUserByUsernameFetch + >['userByUsername']; + type _selectedUserByUsernameHasUsername = Assert< + HasKey + >; + + prefetchUserByUsernameQuery(queryClient, { + variables: { username: 'dev' }, + selection: { + fields: { + id: true, + }, + }, + }); + + // @ts-expect-error selection is required for selection-enabled custom query helpers + fetchUserByUsernameQuery({ variables: { username: 'dev' } }); + // @ts-expect-error variables are required for this custom query helper + fetchUserByUsernameQuery({ selection: { fields: { id: true } } }); + + // Optional variables flow for custom queries without selection support. + fetchStepsRequiredQuery(); + fetchStepsRequiredQuery({ variables: { vlevel: '1', first: 10 } }); + prefetchStepsRequiredQuery(queryClient); + prefetchStepsRequiredQuery(queryClient, { variables: { vlevel: '1' } }); + useStepsRequiredQuery(); + useStepsRequiredQuery({ + variables: { vlevel: '1' }, + enabled: false, + }); + // @ts-expect-error selection is not available on this custom query + useStepsRequiredQuery({ selection: { fields: { id: true } } }); +} + +function reactQueryOptionsChecks() { + useDatabasesQuery({ + selection: { + first: 10, + fields: { + id: true, + name: true, + }, + }, + enabled: true, + staleTime: 30_000, + gcTime: 300_000, + retry: 2, + refetchOnWindowFocus: false, + refetchInterval: false, + refetchOnReconnect: true, + refetchOnMount: 'always', + networkMode: 'always', + notifyOnChangeProps: ['data', 'error'], + meta: { source: 'type-test' }, + }); + + const transformedDatabases = useDatabasesQuery({ + selection: { + first: 10, + fields: { + id: true, + name: true, + }, + }, + select: (data) => data.databases.nodes.map((node) => node.name), + placeholderData: (previousData) => + previousData ?? { + databases: { + nodes: [], + totalCount: 0, + pageInfo: { + hasNextPage: false, + hasPreviousPage: false, + }, + }, + }, + staleTime: (query) => { + const status = query.state.status; + void status; + return 10_000; + }, + throwOnError: (error) => error.message.length > 0, + }); + const transformedDatabaseNames: string[] | undefined = transformedDatabases.data; + void transformedDatabaseNames; + // @ts-expect-error transformed query data should not expose connection shape + transformedDatabases.data.databases; + + const currentUserResult = useCurrentUserQuery({ + selection: { + fields: { + id: true, + username: true, + }, + }, + placeholderData: (previousData) => + previousData ?? { + currentUser: { + id: 'fallback-user-id', + username: 'fallback-user', + }, + }, + enabled: false, + staleTime: 5_000, + gcTime: 60_000, + retry: (failureCount, error) => { + const msg = error.message; + void msg; + return failureCount < 2; + }, + }); + const currentUserId: string | undefined = currentUserResult.data?.currentUser.id; + void currentUserId; + + useUserByUsernameQuery({ + variables: { username: 'dev' }, + selection: { + fields: { + id: true, + }, + }, + enabled: false, + staleTime: 5_000, + }); + + // @ts-expect-error unknown React Query option should be rejected + useDatabasesQuery({ selection: { fields: { id: true } }, unknownOption: true }); + + // @ts-expect-error queryKey is owned by generated hooks + useDatabasesQuery({ selection: { fields: { id: true } }, queryKey: ['override'] as const }); + + useDatabasesQuery({ + selection: { fields: { id: true } }, + // @ts-expect-error queryFn is owned by generated hooks + queryFn: async () => + ({ + databases: { + nodes: [], + totalCount: 0, + pageInfo: { + hasNextPage: false, + hasPreviousPage: false, + }, + }, + }) as never, + }); + + useSignInMutation({ + selection: { + fields: { + clientMutationId: true, + result: { + select: { + accessToken: true, + isVerified: true, + totpEnabled: true, + userId: true, + }, + }, + }, + }, + retry: 1, + gcTime: 300_000, + meta: { source: 'type-test' }, + networkMode: 'always', + throwOnError: (error) => error.message.length > 0, + onMutate: (variables) => { + const email = variables.input.email; + return { email }; + }, + onError: (error, variables, context) => { + const message = error.message; + const rememberMe = variables.input.rememberMe; + void message; + void rememberMe; + void context; + }, + onSuccess: (data, variables) => { + const accessToken = data.signIn.result.accessToken; + const email = variables.input.email; + void accessToken; + void email; + }, + }); + + useSignInMutation({ + selection: { fields: { clientMutationId: true } }, + // @ts-expect-error mutationFn is owned by generated hooks + mutationFn: async () => + ({ + signIn: { + clientMutationId: 'x', + }, + }) as never, + }); +} + +void helperOverloadChecks; +void reactQueryOptionsChecks; diff --git a/graphql/test-app/src/type-tests/react-query-orm-overloads.type-test.ts b/graphql/test-app/src/type-tests/react-query-orm-overloads.type-test.ts new file mode 100644 index 000000000..eea13ad36 --- /dev/null +++ b/graphql/test-app/src/type-tests/react-query-orm-overloads.type-test.ts @@ -0,0 +1,313 @@ +/** + * Compile-time regression checks for React Query + ORM output modes. + * + * These checks focus on overload behavior and nested select contextual typing. + */ + +import { + useCurrentUserQuery, + useSignInMutation, + useUserByUsernameQuery, + useUserQuery, + useUsersQuery, +} from '../generated/hooks'; +import { createClient } from '../generated/orm'; + +type Assert = T; +type HasKey = K extends keyof T ? true : false; +type NotHasKey = K extends keyof T ? false : true; + +const ormClient = createClient({ + endpoint: 'https://example.invalid/graphql', +}); + +function hookTypeChecks() { + const currentUser = useCurrentUserQuery({ + selection: { + fields: { + id: true, + username: true, + }, + }, + }); + + const maybeUsername = currentUser.data?.currentUser.username; + void maybeUsername; + + // @ts-expect-error selection is required + useUserQuery({ id: '00000000-0000-0000-0000-000000000000' }); + + const selectedUser = useUserQuery({ + id: '00000000-0000-0000-0000-000000000000', + selection: { + fields: { + id: true, + username: true, + }, + }, + }); + const selectedUsername = selectedUser.data?.user?.username; + void selectedUsername; + + const users = useUsersQuery({ + selection: { + fields: { + id: true, + username: true, + ownedDatabases: { + first: 2, + select: { + id: true, + schemaName: true, + name: true, + }, + }, + }, + first: 5, + orderBy: ['CREATED_AT_DESC'], + }, + }); + + const nestedSchema = users.data?.users.nodes[0]?.ownedDatabases?.nodes[0]?.schemaName; + void nestedSchema; + + useUserByUsernameQuery({ + variables: { username: 'dev' }, + selection: { + fields: { + id: true, + username: true, + }, + }, + }); + + // @ts-expect-error variables are required for this custom query + useUserByUsernameQuery({ + selection: { fields: { id: true } }, + }); + + // @ts-expect-error selection is required for custom mutation hooks + useSignInMutation(); + + useSignInMutation({ + selection: { + fields: { + clientMutationId: true, + result: { + select: { + accessToken: true, + accessTokenExpiresAt: true, + isVerified: true, + totpEnabled: true, + userId: true, + }, + }, + }, + }, + }); + + const validSignInSelect = { + clientMutationId: true, + result: { + select: { + accessToken: true, + isVerified: true, + totpEnabled: true, + userId: true, + }, + }, + }; + useSignInMutation({ selection: { fields: validSignInSelect } }); + + const invalidUsersSelect = { + id: true, + invalidField: true, + }; + // @ts-expect-error invalid variable select key should be rejected + useUsersQuery({ selection: { fields: invalidUsersSelect } }); + + const invalidNestedUsersSelect = { + ownedDatabases: { + select: { + id: true, + doesNotExist: true, + }, + }, + }; + // @ts-expect-error invalid nested variable select key should be rejected + useUsersQuery({ selection: { fields: invalidNestedUsersSelect } }); + + const invalidCurrentUserSelect = { + id: true, + nope: true, + }; + // @ts-expect-error invalid variable select key should be rejected + useCurrentUserQuery({ selection: { fields: invalidCurrentUserSelect } }); + + const invalidSignInSelect = { + result: { + select: { + accessToken: true, + nope: true, + }, + }, + }; + // @ts-expect-error invalid mutation variable select key should be rejected + useSignInMutation({ selection: { fields: invalidSignInSelect } }); +} + +async function ormModelTypeChecks() { + // @ts-expect-error findOne requires explicit select + ormClient.user.findOne({ + id: '00000000-0000-0000-0000-000000000000', + }); + + const idOnlyBuilder = ormClient.user.findOne({ + id: '00000000-0000-0000-0000-000000000000', + select: { + id: true, + }, + }); + type IdOnlyUser = Awaited>['user']; + type _idOnlyOmitsUsername = Assert, 'username'>>; + + const explicitlySelected = ormClient.user.findOne({ + id: '00000000-0000-0000-0000-000000000000', + select: { + id: true, + username: true, + ownedDatabases: { + first: 1, + select: { + id: true, + schemaName: true, + }, + }, + }, + }); + + type ExplicitUser = Awaited>['user']; + type _explicitHasUsername = Assert, 'username'>>; + + ormClient.user.findMany({ + first: 5, + select: { + id: true, + username: true, + ownedDatabases: { + first: 1, + select: { + id: true, + schemaName: true, + }, + }, + }, + }); + + ormClient.query.currentUser({ + select: { + id: true, + username: true, + ownedDatabases: { + first: 1, + select: { + id: true, + }, + }, + }, + }); + // @ts-expect-error custom ORM query requires options with select + ormClient.query.currentUser(); + + ormClient.query.userByUsername( + { + username: 'dev', + }, + { + select: { + id: true, + }, + }, + ); + // @ts-expect-error custom ORM query requires options with select + ormClient.query.userByUsername({ + username: 'dev', + }); + + ormClient.mutation.signIn( + { + input: { + email: 'dev@example.com', + password: 'password', + rememberMe: true, + }, + }, + { + select: { + clientMutationId: true, + result: { + select: { + accessToken: true, + userId: true, + }, + }, + }, + }, + ); + // @ts-expect-error custom ORM mutation requires options with select + ormClient.mutation.signIn({ + input: { + email: 'dev@example.com', + password: 'password', + rememberMe: true, + }, + }); + + const invalidModelSelect = { + id: true, + invalidField: true, + }; + // @ts-expect-error invalid model variable select key should be rejected + ormClient.user.findMany({ select: invalidModelSelect }); + + const invalidNestedModelSelect = { + ownedDatabases: { + select: { + id: true, + invalidField: true, + }, + }, + }; + // @ts-expect-error invalid nested model variable select key should be rejected + ormClient.user.findMany({ select: invalidNestedModelSelect }); + + const invalidCustomQuerySelect = { + id: true, + invalidField: true, + }; + // @ts-expect-error invalid custom query variable select key should be rejected + ormClient.query.currentUser({ select: invalidCustomQuerySelect }); + + const invalidCustomMutationSelect = { + result: { + select: { + accessToken: true, + invalidField: true, + }, + }, + }; + ormClient.mutation.signIn( + { + input: { + email: 'dev@example.com', + password: 'password', + rememberMe: true, + }, + }, + // @ts-expect-error invalid custom mutation variable select key should be rejected + { select: invalidCustomMutationSelect }, + ); +} + +void hookTypeChecks; +void ormModelTypeChecks; diff --git a/graphql/test-app/src/type-tests/select-strictness-regressions.type-test.ts b/graphql/test-app/src/type-tests/select-strictness-regressions.type-test.ts new file mode 100644 index 000000000..926dbd653 --- /dev/null +++ b/graphql/test-app/src/type-tests/select-strictness-regressions.type-test.ts @@ -0,0 +1,204 @@ +/** + * Additional compile-time regression checks focused on strict selection behavior. + */ + +import { useDatabasesQuery, useSignInMutation } from '../generated/hooks'; +import { createClient } from '../generated/orm'; + +type Assert = T; +type HasKey = K extends keyof T ? true : false; +type NotHasKey = K extends keyof T ? false : true; + +const ormClient = createClient({ + endpoint: 'https://example.invalid/graphql', +}); + +function hookStrictnessChecks() { + // @ts-expect-error selection.fields is required + useDatabasesQuery({ selection: { first: 10 } }); + + const selectedDatabases = useDatabasesQuery({ + selection: { + first: 10, + where: { + and: [ + { name: { includesInsensitive: 'prod' } }, + { createdAt: { greaterThanOrEqualTo: '2026-01-01T00:00:00.000Z' } }, + ], + }, + orderBy: ['CREATED_AT_DESC'], + fields: { + id: true, + name: true, + schemas: { + first: 5, + filter: { + schemaName: { startsWithInsensitive: 'app_' }, + isPublic: { equalTo: true }, + }, + orderBy: ['SCHEMA_NAME_ASC'], + select: { + id: true, + schemaName: true, + isPublic: true, + }, + }, + }, + }, + }); + const selectedDatabaseName = selectedDatabases.data?.databases.nodes[0]?.name; + const selectedNestedSchema = selectedDatabases.data?.databases.nodes[0]?.schemas?.nodes[0]?.schemaName; + void selectedDatabaseName; + void selectedNestedSchema; + + useDatabasesQuery({ + // @ts-expect-error relation select options should use filter, not where + selection: { + fields: { + schemas: { + where: { + schemaName: { equalTo: 'public' }, + }, + select: { + id: true, + }, + }, + }, + }, + }); + + useDatabasesQuery({ + selection: { + fields: { + schemas: { + filter: { + // @ts-expect-error invalid field inside nested relation filter should be rejected + invalidField: { equalTo: 'x' }, + }, + select: { + id: true, + }, + }, + }, + }, + }); + + useDatabasesQuery({ + selection: { + fields: { + schemas: { + // @ts-expect-error invalid orderBy literal should be rejected + orderBy: ['INVALID_ASC'], + select: { + id: true, + }, + }, + }, + }, + }); + + const invalidDatabaseSelect = { + id: true, + invalidField: true, + }; + // @ts-expect-error invalid variable select field should be rejected + useDatabasesQuery({ selection: { fields: invalidDatabaseSelect } }); + + const invalidNestedDatabaseSelect = { + schemas: { + select: { + id: true, + invalidField: true, + }, + }, + }; + // @ts-expect-error invalid nested variable select field should be rejected + useDatabasesQuery({ selection: { fields: invalidNestedDatabaseSelect } }); + + const validSignInSelect = { + clientMutationId: true, + result: { + select: { + accessToken: true, + userId: true, + }, + }, + }; + useSignInMutation({ selection: { fields: validSignInSelect } }); + + const invalidSignInNested = { + clientMutationId: true, + result: { + select: { + accessToken: true, + invalidNestedField: true, + }, + }, + }; + // @ts-expect-error invalid nested variable select field should be rejected + useSignInMutation({ selection: { fields: invalidSignInNested } }); +} + +async function ormStrictnessChecks() { + const selectedCurrentUser = ormClient.query.currentUser({ + select: { + id: true, + }, + }); + type SelectedCurrentUser = Awaited>['currentUser']; + type _selectedCurrentUserOmitsUsername = Assert< + NotHasKey + >; + + const selectedCurrentUserWithUsername = ormClient.query.currentUser({ + select: { + id: true, + username: true, + }, + }); + type SelectedCurrentUserWithUsername = Awaited< + ReturnType + >['currentUser']; + type _selectedCurrentUserHasUsername = Assert< + HasKey + >; + + // @ts-expect-error custom ORM query requires options with select + ormClient.query.currentUser(); + + ormClient.mutation.signIn( + { + input: { + email: 'dev@example.com', + password: 'password', + rememberMe: true, + }, + }, + { + select: { + clientMutationId: true, + result: { + select: { + accessToken: true, + userId: true, + }, + }, + }, + }, + ); + + ormClient.mutation.signIn( + { + input: { + email: 'dev@example.com', + password: 'password', + rememberMe: true, + }, + }, + // @ts-expect-error custom ORM mutation options require select + {}, + ); +} + +void hookStrictnessChecks; +void ormStrictnessChecks; diff --git a/graphql/test-app/src/vite-env.d.ts b/graphql/test-app/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/graphql/test-app/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/graphql/test-app/tests/hook-test-utils.ts b/graphql/test-app/tests/hook-test-utils.ts new file mode 100644 index 000000000..a2957109f --- /dev/null +++ b/graphql/test-app/tests/hook-test-utils.ts @@ -0,0 +1,85 @@ +import assert from 'node:assert/strict'; + +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import React from 'react'; +import { act, create, type ReactTestRenderer } from 'react-test-renderer'; + +type WaitForOptions = { + timeoutMs?: number; + intervalMs?: number; +}; + +export interface HookHarness { + getResult: () => TResult; + waitFor: (predicate: (result: TResult) => boolean, options?: WaitForOptions) => Promise; + unmount: () => Promise; +} + +const DEFAULT_TIMEOUT_MS = 20_000; +const DEFAULT_INTERVAL_MS = 30; + +function sleep(ms: number): Promise { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); +} + +export async function renderHookWithClient( + useHook: () => TResult, + queryClient: QueryClient +): Promise> { + // Enables React's act() environment checks for non-Jest runtimes. + (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; + + let renderer: ReactTestRenderer | null = null; + let latestResult: TResult | undefined; + + function Probe() { + latestResult = useHook(); + return null; + } + + await act(async () => { + renderer = create( + React.createElement( + QueryClientProvider, + { client: queryClient }, + React.createElement(Probe, null) + ) + ); + }); + + return { + getResult() { + assert.notEqual(latestResult, undefined, 'Hook result is not ready yet'); + return latestResult; + }, + + async waitFor(predicate, options) { + const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS; + const intervalMs = options?.intervalMs ?? DEFAULT_INTERVAL_MS; + const start = Date.now(); + + while (Date.now() - start < timeoutMs) { + const result = this.getResult(); + if (predicate(result)) { + return result; + } + await act(async () => { + await sleep(intervalMs); + }); + } + + throw new Error(`Timed out waiting for hook condition after ${timeoutMs}ms`); + }, + + async unmount() { + if (!renderer) { + return; + } + await act(async () => { + renderer?.unmount(); + }); + }, + }; +} diff --git a/graphql/test-app/tests/hooks.live.test.ts b/graphql/test-app/tests/hooks.live.test.ts new file mode 100644 index 000000000..d780a88b4 --- /dev/null +++ b/graphql/test-app/tests/hooks.live.test.ts @@ -0,0 +1,341 @@ +import assert from 'node:assert/strict'; +import { after, before, describe, test } from 'node:test'; + +import { act } from 'react-test-renderer'; + +import { + currentUserIdQueryKey, + currentUserQueryKey, + fetchCurrentUserIdQuery, + fetchCurrentUserQuery, + fetchUserQuery, + fetchUsersQuery, + prefetchCurrentUserIdQuery, + prefetchCurrentUserQuery, + prefetchUserQuery, + prefetchUsersQuery, + useCheckPasswordMutation, + useCurrentUserIdQuery, + useCurrentUserQuery, + useSignInMutation, + useSignOutMutation, + useUserQuery, + useUsersQuery, + userQueryKey, + usersQueryKey, +} from '../src/generated/hooks'; + +import { renderHookWithClient } from './hook-test-utils'; +import { + assertLiveEnvConfigured, + configureHooks, + createTestQueryClient, + getLiveEnvHelpMessage, + getLiveTestEnv, + type AuthSession, + signIn, + signOut, +} from './live-test-utils'; + +const liveEnv = getLiveTestEnv(); +assertLiveEnvConfigured(liveEnv); + +if (!liveEnv) { + test.skip(getLiveEnvHelpMessage(), () => {}); +} else { + describe('React Query Hooks (live endpoint)', () => { + let sharedSession: AuthSession | null = null; + + const ensureAuth = async (): Promise => { + if (!sharedSession) { + sharedSession = await signIn(liveEnv); + } + configureHooks(liveEnv, sharedSession.token); + return sharedSession; + }; + + before(() => { + configureHooks(liveEnv); + }); + + after(async () => { + if (sharedSession) { + await signOut(liveEnv, sharedSession.token); + sharedSession = null; + } + configureHooks(liveEnv); + }); + + test('useSignInMutation returns token payload when explicit select is provided', async () => { + const queryClient = createTestQueryClient(); + const hook = await renderHookWithClient( + () => + useSignInMutation({ + select: { + result: { + select: { + accessToken: true, + userId: true, + isVerified: true, + totpEnabled: true, + }, + }, + }, + }), + queryClient + ); + + let result: + | { + signIn: { + result?: { + accessToken?: string | null; + userId?: string | null; + isVerified?: boolean | null; + totpEnabled?: boolean | null; + } | null; + }; + } + | null = null; + + await act(async () => { + result = await hook.getResult().mutateAsync({ + input: { + email: liveEnv.email, + password: liveEnv.password, + rememberMe: true, + }, + }); + }); + + const token = result?.signIn.result?.accessToken ?? null; + const userId = result?.signIn.result?.userId ?? null; + assert.ok(token, 'useSignInMutation did not return accessToken'); + assert.ok(userId, 'useSignInMutation did not return userId'); + + await signOut(liveEnv, token); + await hook.unmount(); + queryClient.clear(); + }); + + test('useCurrentUserQuery returns nested selected relation fields', async () => { + await ensureAuth(); + const queryClient = createTestQueryClient(); + const hook = await renderHookWithClient( + () => + useCurrentUserQuery({ + select: { + id: true, + username: true, + databasesByOwnerId: { + first: 1, + select: { + id: true, + schemaName: true, + }, + }, + }, + }), + queryClient + ); + + const result = await hook.waitFor((value) => value.isSuccess || value.isError); + assert.equal(result.isError, false, 'useCurrentUserQuery returned an error'); + assert.ok(result.data?.currentUser?.id, 'currentUser.id is missing'); + assert.ok( + Array.isArray(result.data?.currentUser?.databasesByOwnerId?.nodes), + 'currentUser.databasesByOwnerId.nodes should be an array' + ); + + await hook.unmount(); + queryClient.clear(); + }); + + test('useCurrentUserIdQuery matches useCurrentUserQuery id', async () => { + const session = await ensureAuth(); + const queryClient = createTestQueryClient(); + const hook = await renderHookWithClient(() => useCurrentUserIdQuery(), queryClient); + + const result = await hook.waitFor((value) => value.isSuccess || value.isError); + assert.equal(result.isError, false, 'useCurrentUserIdQuery returned an error'); + assert.equal(result.data?.currentUserId, session.userId, 'currentUserId does not match signed in user'); + + await hook.unmount(); + queryClient.clear(); + }); + + test('useUsersQuery and useUserQuery execute with select overloads', async () => { + const session = await ensureAuth(); + const queryClient = createTestQueryClient(); + + const usersHook = await renderHookWithClient( + () => + useUsersQuery({ + first: 5, + orderBy: ['CREATED_AT_DESC'], + select: { + id: true, + username: true, + databasesByOwnerId: { + first: 1, + select: { + id: true, + }, + }, + }, + }), + queryClient + ); + + const usersResult = await usersHook.waitFor((value) => value.isSuccess || value.isError); + assert.equal(usersResult.isError, false, 'useUsersQuery returned an error'); + assert.ok(Array.isArray(usersResult.data?.users.nodes), 'users.nodes should be an array'); + + const userHook = await renderHookWithClient( + () => + useUserQuery({ + id: session.userId, + select: { + id: true, + username: true, + }, + }), + queryClient + ); + + const userResult = await userHook.waitFor((value) => value.isSuccess || value.isError); + assert.equal(userResult.isError, false, 'useUserQuery returned an error'); + assert.equal(userResult.data?.user?.id, session.userId, 'useUserQuery did not return the requested user'); + + await usersHook.unmount(); + await userHook.unmount(); + queryClient.clear(); + }); + + test('fetch/prefetch helpers populate QueryClient cache with expected keys', async () => { + const session = await ensureAuth(); + const queryClient = createTestQueryClient(); + + const currentUser = await fetchCurrentUserQuery({ + select: { + id: true, + username: true, + }, + }); + assert.equal(currentUser.currentUser.id, session.userId, 'fetchCurrentUserQuery returned unexpected user'); + + const currentUserId = await fetchCurrentUserIdQuery(); + assert.equal(currentUserId.currentUserId, session.userId, 'fetchCurrentUserIdQuery returned unexpected user'); + + const usersArgs = { + first: 3, + select: { + id: true, + username: true, + }, + } as const; + const usersData = await fetchUsersQuery(usersArgs); + assert.ok(Array.isArray(usersData.users.nodes), 'fetchUsersQuery users.nodes should be an array'); + + const userData = await fetchUserQuery({ + id: session.userId, + select: { + id: true, + username: true, + }, + }); + assert.equal(userData.user?.id, session.userId, 'fetchUserQuery returned unexpected user'); + + await prefetchCurrentUserQuery(queryClient, { + select: { + id: true, + username: true, + }, + }); + await prefetchCurrentUserIdQuery(queryClient); + await prefetchUsersQuery(queryClient, usersArgs); + await prefetchUserQuery(queryClient, { id: session.userId }); + + assert.ok(queryClient.getQueryData(currentUserQueryKey()), 'currentUser cache entry missing'); + assert.ok(queryClient.getQueryData(currentUserIdQueryKey()), 'currentUserId cache entry missing'); + assert.ok(queryClient.getQueryData(usersQueryKey(usersArgs)), 'users cache entry missing'); + assert.ok( + queryClient.getQueryData(userQueryKey(session.userId)), + 'user detail cache entry missing' + ); + + queryClient.clear(); + }); + + test('useCheckPasswordMutation succeeds for the signed-in user', async () => { + await ensureAuth(); + const queryClient = createTestQueryClient(); + const hook = await renderHookWithClient( + () => + useCheckPasswordMutation({ + select: { + clientMutationId: true, + }, + }), + queryClient + ); + + let result: + | { + checkPassword: { + clientMutationId?: string | null; + }; + } + | null = null; + + await act(async () => { + result = await hook.getResult().mutateAsync({ + input: { + password: liveEnv.password, + }, + }); + }); + + assert.ok(result?.checkPassword, 'useCheckPasswordMutation returned empty payload'); + + await hook.unmount(); + queryClient.clear(); + }); + + test('useSignOutMutation signs out current session', async () => { + const session = await ensureAuth(); + const queryClient = createTestQueryClient(); + const hook = await renderHookWithClient( + () => + useSignOutMutation({ + select: { + clientMutationId: true, + }, + }), + queryClient + ); + + let result: + | { + signOut: { + clientMutationId?: string | null; + }; + } + | null = null; + + await act(async () => { + result = await hook.getResult().mutateAsync({ + input: {}, + }); + }); + + assert.ok(result?.signOut, 'useSignOutMutation returned empty payload'); + sharedSession = null; + configureHooks(liveEnv); + await signOut(liveEnv, session.token); + + await hook.unmount(); + queryClient.clear(); + }); + }); +} diff --git a/graphql/test-app/tests/live-test-utils.ts b/graphql/test-app/tests/live-test-utils.ts new file mode 100644 index 000000000..9befa2135 --- /dev/null +++ b/graphql/test-app/tests/live-test-utils.ts @@ -0,0 +1,130 @@ +import assert from 'node:assert/strict'; + +import { QueryClient } from '@tanstack/react-query'; + +import { configure } from '../src/generated/hooks/client'; +import { createClient } from '../src/generated/orm'; + +export interface LiveTestEnv { + endpoint: string; + email: string; + password: string; +} + +const DEFAULT_ENDPOINT = 'https://api.launchql.dev/graphql'; + +export function getLiveTestEnv(): LiveTestEnv | null { + const email = process.env.GRAPHQL_TEST_EMAIL; + const password = process.env.GRAPHQL_TEST_PASSWORD; + const endpoint = process.env.GRAPHQL_TEST_ENDPOINT ?? DEFAULT_ENDPOINT; + + if (!email || !password) { + return null; + } + + return { + endpoint, + email, + password, + }; +} + +export function getLiveEnvHelpMessage(): string { + return ( + 'Live tests require GRAPHQL_TEST_EMAIL and GRAPHQL_TEST_PASSWORD. ' + + `Optional GRAPHQL_TEST_ENDPOINT (default: ${DEFAULT_ENDPOINT}).` + ); +} + +export function assertLiveEnvConfigured( + env: LiveTestEnv | null +): asserts env is LiveTestEnv { + if (!env) { + if (process.env.GRAPHQL_TEST_LIVE_REQUIRED === '1') { + throw new Error(getLiveEnvHelpMessage()); + } + } +} + +export function createTestQueryClient(): QueryClient { + return new QueryClient({ + defaultOptions: { + queries: { + retry: false, + refetchOnWindowFocus: false, + }, + mutations: { + retry: false, + }, + }, + }); +} + +export function configureHooks(env: LiveTestEnv, token?: string): void { + configure({ + endpoint: env.endpoint, + headers: token ? { Authorization: `Bearer ${token}` } : {}, + }); +} + +export interface AuthSession { + token: string; + userId: string; +} + +export async function signIn(env: LiveTestEnv): Promise { + const client = createClient({ endpoint: env.endpoint }); + const result = await client.mutation + .signIn( + { + input: { + email: env.email, + password: env.password, + rememberMe: true, + }, + }, + { + select: { + result: { + select: { + accessToken: true, + userId: true, + isVerified: true, + totpEnabled: true, + }, + }, + }, + } + ) + .unwrap(); + + const token = result.signIn.result?.accessToken ?? null; + const userId = result.signIn.result?.userId ?? null; + + assert.ok(token, 'signIn did not return accessToken'); + assert.ok(userId, 'signIn did not return userId'); + + return { token, userId }; +} + +export async function signOut(env: LiveTestEnv, token: string): Promise { + const client = createClient({ + endpoint: env.endpoint, + headers: { Authorization: `Bearer ${token}` }, + }); + + try { + await client.mutation + .signOut( + { input: {} }, + { + select: { + clientMutationId: true, + }, + } + ) + .unwrap(); + } catch { + // Best-effort cleanup: token might already be invalidated. + } +} diff --git a/graphql/test-app/tests/orm.live.test.ts b/graphql/test-app/tests/orm.live.test.ts new file mode 100644 index 000000000..d40952864 --- /dev/null +++ b/graphql/test-app/tests/orm.live.test.ts @@ -0,0 +1,232 @@ +import assert from 'node:assert/strict'; +import { after, describe, test } from 'node:test'; + +import { createClient } from '../src/generated/orm'; + +import { + assertLiveEnvConfigured, + getLiveEnvHelpMessage, + getLiveTestEnv, + type AuthSession, + signIn, + signOut, +} from './live-test-utils'; + +const liveEnv = getLiveTestEnv(); +assertLiveEnvConfigured(liveEnv); + +if (!liveEnv) { + test.skip(getLiveEnvHelpMessage(), () => {}); +} else { + describe('ORM Client (live endpoint)', () => { + let sharedSession: AuthSession | null = null; + + const ensureAuth = async (): Promise => { + if (!sharedSession) { + sharedSession = await signIn(liveEnv); + } + return sharedSession; + }; + + const createAuthedClient = async () => { + const session = await ensureAuth(); + return createClient({ + endpoint: liveEnv.endpoint, + headers: { Authorization: `Bearer ${session.token}` }, + }); + }; + + after(async () => { + if (sharedSession) { + await signOut(liveEnv, sharedSession.token); + sharedSession = null; + } + }); + + test('custom signIn mutation returns token with explicit select', async () => { + const client = createClient({ endpoint: liveEnv.endpoint }); + const result = await client.mutation + .signIn( + { + input: { + email: liveEnv.email, + password: liveEnv.password, + rememberMe: true, + }, + }, + { + select: { + result: { + select: { + accessToken: true, + userId: true, + isVerified: true, + }, + }, + }, + } + ) + .unwrap(); + + const token = result.signIn.result?.accessToken ?? null; + assert.ok(token, 'ORM signIn did not return accessToken'); + await signOut(liveEnv, token); + }); + + test('custom signIn mutation default select path returns payload shape', async () => { + const client = createClient({ endpoint: liveEnv.endpoint }); + + const result = await client.mutation.signIn( + { + input: { + email: liveEnv.email, + password: liveEnv.password, + rememberMe: true + } + }, + { + select: { + clientMutationId: true, + result: { + select: { + accessToken: true, + userId: true, + isVerified: true, + totpEnabled: true, + }, + }, + }, + } + ).unwrap(); + + assert.ok(result.signIn, 'Default signIn payload is missing'); + assert.ok(result.signIn?.result?.accessToken, 'Default signIn result is missing accessToken'); + await ensureAuth(); + }); + + test('model findMany builds expected GraphQL and executes nested select', async () => { + const client = await createAuthedClient(); + + const builder = client.user.findMany({ + first: 5, + orderBy: ['CREATED_AT_DESC'], + select: { + id: true, + username: true, + databasesByOwnerId: { + first: 1, + select: { + id: true, + schemaName: true, + }, + }, + }, + }); + + const graphql = builder.toGraphQL(); + const variables = builder.getVariables() ?? {}; + assert.match(graphql, /query UserQuery/); + assert.match(graphql, /users\(/); + assert.match(graphql, /databasesByOwnerId\(first: 1\)/); + assert.equal(variables.first, 5, 'findMany first variable should be emitted'); + + const result = await builder.unwrap(); + assert.ok(Array.isArray(result.users.nodes), 'users.nodes should be an array'); + }); + + test('model findOne overloads work for default and explicit select', async () => { + const session = await ensureAuth(); + const client = await createAuthedClient(); + + const defaultResult = await client.user.findOne({ id: session.userId }).unwrap(); + assert.equal(defaultResult.user?.id, session.userId, 'findOne default select returned wrong user'); + + const explicitResult = await client.user + .findOne({ + id: session.userId, + select: { + id: true, + username: true, + displayName: true, + }, + }) + .unwrap(); + + assert.equal(explicitResult.user?.id, session.userId, 'findOne explicit select returned wrong user'); + }); + + test('model findFirst and custom currentUser/currentUserId queries execute', async () => { + const session = await ensureAuth(); + const client = await createAuthedClient(); + + const firstResult = await client.user + .findFirst({ + select: { + id: true, + username: true, + }, + }) + .unwrap(); + assert.ok(Array.isArray(firstResult.users.nodes), 'findFirst should return users.nodes array'); + + const currentUserResult = await client.query + .currentUser({ + select: { + id: true, + username: true, + }, + }) + .unwrap(); + assert.equal( + currentUserResult.currentUser.id, + session.userId, + 'currentUser query returned unexpected user' + ); + + const currentUserIdResult = await client.query.currentUserId().unwrap(); + assert.equal( + currentUserIdResult.currentUserId, + session.userId, + 'currentUserId query returned unexpected user' + ); + }); + + test('custom checkPassword and signOut mutations execute successfully', async () => { + const session = await ensureAuth(); + const client = await createAuthedClient(); + + const checkPasswordResult = await client.mutation + .checkPassword( + { + input: { + password: liveEnv.password, + }, + }, + { + select: { + clientMutationId: true, + }, + } + ) + .unwrap(); + assert.ok(checkPasswordResult.checkPassword, 'checkPassword payload missing'); + + const signOutResult = await client.mutation + .signOut( + { + input: {}, + }, + { + select: { + clientMutationId: true, + }, + } + ) + .unwrap(); + assert.ok(signOutResult.signOut, 'signOut payload missing'); + + sharedSession = null; + await signOut(liveEnv, session.token); + }); + }); +} diff --git a/graphql/test-app/tsconfig.json b/graphql/test-app/tsconfig.json new file mode 100644 index 000000000..4bad3d23e --- /dev/null +++ b/graphql/test-app/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2023", "DOM", "DOM.Iterable"], + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "strictNullChecks": false, + "noEmit": true, + "esModuleInterop": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "resolveJsonModule": true, + "isolatedModules": true, + "allowImportingTsExtensions": true + }, + "include": ["src"] +} diff --git a/graphql/test-app/vite.config.ts b/graphql/test-app/vite.config.ts new file mode 100644 index 000000000..2e3f72d38 --- /dev/null +++ b/graphql/test-app/vite.config.ts @@ -0,0 +1,19 @@ +import react from '@vitejs/plugin-react'; +import { defineConfig } from 'vite'; +import { visualizer } from 'rollup-plugin-visualizer'; + +export default defineConfig({ + plugins: [ + react(), + visualizer({ + filename: 'dist/bundle-stats.html', + open: false, + gzipSize: true, + brotliSize: true, + template: 'treemap', + }), + ], + server: { + port: 5199, + }, +}); diff --git a/graphql/test/package.json b/graphql/test/package.json index df52a84a2..46d030073 100644 --- a/graphql/test/package.json +++ b/graphql/test/package.json @@ -31,7 +31,7 @@ "devDependencies": { "@types/pg": "^8.16.0", "graphql-tag": "2.12.6", - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@constructive-io/graphql-env": "workspace:^", diff --git a/graphql/types/package.json b/graphql/types/package.json index d04a2ba02..1751ef21f 100644 --- a/graphql/types/package.json +++ b/graphql/types/package.json @@ -44,6 +44,6 @@ "graphile" ], "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/jobs/job-pg/package.json b/jobs/job-pg/package.json index 7a325007b..45009ca13 100644 --- a/jobs/job-pg/package.json +++ b/jobs/job-pg/package.json @@ -33,7 +33,7 @@ "url": "https://github.com/constructive-io/jobs/issues" }, "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@constructive-io/job-utils": "workspace:^", diff --git a/jobs/job-scheduler/package.json b/jobs/job-scheduler/package.json index 8b9091f5d..d5a8110e8 100644 --- a/jobs/job-scheduler/package.json +++ b/jobs/job-scheduler/package.json @@ -33,7 +33,7 @@ "url": "https://github.com/constructive-io/jobs/issues" }, "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@constructive-io/job-pg": "workspace:^", diff --git a/jobs/job-utils/package.json b/jobs/job-utils/package.json index 16ac237c1..ae76127ce 100644 --- a/jobs/job-utils/package.json +++ b/jobs/job-utils/package.json @@ -33,7 +33,7 @@ "url": "https://github.com/constructive-io/jobs/issues" }, "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@pgpmjs/env": "workspace:^", diff --git a/jobs/job-worker/package.json b/jobs/job-worker/package.json index c21d71666..a8af763b5 100644 --- a/jobs/job-worker/package.json +++ b/jobs/job-worker/package.json @@ -33,7 +33,7 @@ "url": "https://github.com/constructive-io/jobs/issues" }, "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@constructive-io/job-utils": "workspace:^", diff --git a/jobs/knative-job-example/package.json b/jobs/knative-job-example/package.json index 1c60dc8c9..25d7c14a7 100644 --- a/jobs/knative-job-example/package.json +++ b/jobs/knative-job-example/package.json @@ -34,7 +34,7 @@ "url": "https://github.com/constructive-io/jobs/issues" }, "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@constructive-io/knative-job-fn": "workspace:^" diff --git a/jobs/knative-job-fn/package.json b/jobs/knative-job-fn/package.json index 6c5326ff4..af7a37730 100644 --- a/jobs/knative-job-fn/package.json +++ b/jobs/knative-job-fn/package.json @@ -33,7 +33,7 @@ "url": "https://github.com/constructive-io/jobs/issues" }, "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@pgpmjs/logger": "workspace:^", diff --git a/jobs/knative-job-server/package.json b/jobs/knative-job-server/package.json index a5d964e00..9a4fd19d4 100644 --- a/jobs/knative-job-server/package.json +++ b/jobs/knative-job-server/package.json @@ -36,7 +36,7 @@ "url": "https://github.com/constructive-io/jobs/issues" }, "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@constructive-io/job-pg": "workspace:^", diff --git a/jobs/knative-job-service/package.json b/jobs/knative-job-service/package.json index df6afc17e..f2bd97507 100644 --- a/jobs/knative-job-service/package.json +++ b/jobs/knative-job-service/package.json @@ -50,7 +50,7 @@ "@pgpm/verify": "^0.16.0", "@pgpmjs/core": "workspace:^", "@types/supertest": "^6.0.3", - "makage": "^0.1.10", + "makage": "^0.1.12", "pgsql-test": "workspace:^", "supertest": "^7.2.2", "ts-node": "^10.9.2" diff --git a/jobs/knative-job-worker/package.json b/jobs/knative-job-worker/package.json index faa67169b..27cff01a7 100644 --- a/jobs/knative-job-worker/package.json +++ b/jobs/knative-job-worker/package.json @@ -47,7 +47,7 @@ "@pgpm/database-jobs": "^0.16.0", "@pgpm/verify": "^0.16.0", "@pgpmjs/core": "workspace:^", - "makage": "^0.1.10", + "makage": "^0.1.12", "pgsql-test": "workspace:^" } } diff --git a/package.json b/package.json index 6ef5a5fb4..9c215bbf4 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "jest": "^30.2.0", "jest-in-case": "^1.0.2", "lerna": "^8.2.3", - "makage": "^0.1.10", + "makage": "^0.1.12", "prettier": "^3.8.0", "ts-jest": "^29.4.6", "ts-node": "^10.9.2", diff --git a/packages/12factor-env/package.json b/packages/12factor-env/package.json index 251c77839..8eca35a8f 100644 --- a/packages/12factor-env/package.json +++ b/packages/12factor-env/package.json @@ -33,7 +33,7 @@ }, "devDependencies": { "@types/node": "^20.12.7", - "makage": "^0.1.10", + "makage": "^0.1.12", "ts-node": "^10.9.2" }, "keywords": [ diff --git a/packages/cli/__tests__/codegen.test.ts b/packages/cli/__tests__/codegen.test.ts index 5fa4bcc48..c61cdc34b 100644 --- a/packages/cli/__tests__/codegen.test.ts +++ b/packages/cli/__tests__/codegen.test.ts @@ -15,16 +15,18 @@ jest.mock('@constructive-io/graphql-codegen', () => { return { generate: jest.fn(async () => ({ success: true, message: 'Generated SDK', filesWritten: [] as string[] })), findConfigFile: jest.fn((): string | undefined => undefined), + loadConfigFile: jest.fn(async () => ({ success: false, error: 'not found' })), + splitCommas: splitCommasMock, codegenQuestions: [ { name: 'endpoint', message: 'GraphQL endpoint URL', type: 'text', required: false }, - { name: 'schemaFile', message: 'Path to GraphQL schema file', type: 'text', required: false }, + { name: 'schema-file', message: 'Path to GraphQL schema file', type: 'text', required: false }, { name: 'output', message: 'Output directory', type: 'text', required: false, default: 'codegen', useDefault: true }, { name: 'schemas', message: 'PostgreSQL schemas', type: 'text', required: false, sanitize: splitCommasMock }, - { name: 'apiNames', message: 'API names', type: 'text', required: false, sanitize: splitCommasMock }, - { name: 'reactQuery', message: 'Generate React Query hooks?', type: 'confirm', required: false, default: false, useDefault: true }, + { name: 'api-names', message: 'API names', type: 'text', required: false, sanitize: splitCommasMock }, + { name: 'react-query', message: 'Generate React Query hooks?', type: 'confirm', required: false, default: false, useDefault: true }, { name: 'orm', message: 'Generate ORM client?', type: 'confirm', required: false, default: false, useDefault: true }, { name: 'authorization', message: 'Authorization header value', type: 'text', required: false }, - { name: 'dryRun', message: 'Preview without writing files?', type: 'confirm', required: false, default: false, useDefault: true }, + { name: 'dry-run', message: 'Preview without writing files?', type: 'confirm', required: false, default: false, useDefault: true }, { name: 'verbose', message: 'Verbose output?', type: 'confirm', required: false, default: false, useDefault: true }, ], printResult: jest.fn((result: any) => { @@ -36,6 +38,31 @@ jest.mock('@constructive-io/graphql-codegen', () => { } }), camelizeArgv: jest.fn((argv: Record) => argv), + seedArgvFromConfig: jest.fn((argv: Record, _fileConfig: any) => argv), + hasResolvedCodegenSource: jest.fn((argv: Record) => { + const db = argv.db as Record | undefined; + return Boolean( + argv.endpoint || + argv['schema-file'] || + argv.schemas || + argv['api-names'] || + db?.schemas || + db?.apiNames + ); + }), + buildGenerateOptions: jest.fn((answers: Record, _fileConfig: any) => { + const { schemas, apiNames, ...rest } = answers; + const normalizedSchemas = Array.isArray(schemas) + ? schemas + : splitCommasMock(schemas as string | undefined); + const normalizedApiNames = Array.isArray(apiNames) + ? apiNames + : splitCommasMock(apiNames as string | undefined); + if (schemas || apiNames) { + return { ...rest, db: { schemas: normalizedSchemas, apiNames: normalizedApiNames } }; + } + return rest; + }), }; }) @@ -91,6 +118,7 @@ describe('codegen command', () => { await codegenCommand(argv, mockPrompter as any, {} as any) + expect(mockPrompter.prompt).not.toHaveBeenCalled() expect(mockGenerate).toHaveBeenCalled() const call = mockGenerate.mock.calls[0][0] expect(call).toMatchObject({ @@ -115,6 +143,7 @@ describe('codegen command', () => { await codegenCommand(argv, mockPrompter as any, {} as any) + expect(mockPrompter.prompt).not.toHaveBeenCalled() expect(mockGenerate).toHaveBeenCalled() const call = mockGenerate.mock.calls[0][0] expect(call.db).toEqual({ schemas: ['public', 'app'], apiNames: undefined }) diff --git a/packages/cli/package.json b/packages/cli/package.json index fed983580..4dc2500c2 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -40,7 +40,7 @@ "@types/pg": "^8.16.0", "@types/shelljs": "^0.8.16", "glob": "^13.0.0", - "makage": "^0.1.10", + "makage": "^0.1.12", "pg": "^8.17.1", "ts-node": "^10.9.2" }, diff --git a/packages/cli/src/commands/codegen.ts b/packages/cli/src/commands/codegen.ts index 0d41bccae..58d47abe7 100644 --- a/packages/cli/src/commands/codegen.ts +++ b/packages/cli/src/commands/codegen.ts @@ -2,10 +2,13 @@ import { CLIOptions, Inquirerer } from 'inquirerer'; import { generate, findConfigFile, + loadConfigFile, codegenQuestions, printResult, - camelizeArgv, - type CodegenAnswers, + buildGenerateOptions, + seedArgvFromConfig, + hasResolvedCodegenSource, + type GraphQLSDKConfigTarget, } from '@constructive-io/graphql-codegen'; const usage = ` @@ -27,8 +30,6 @@ Generator Options: --orm Generate ORM client --output Output directory (default: codegen) --authorization Authorization header value - --browser-compatible Generate browser-compatible code (default: true) - Set to false for Node.js with localhost DNS fix --dry-run Preview without writing files --verbose Verbose output @@ -45,38 +46,28 @@ export default async ( process.exit(0); } - // Auto-detect config file if not provided - const config = argv.config || findConfigFile(); - if (config) { - // If config file exists, just run generate with it (config file handles everything) - const result = await generate({}); - printResult(result); - return; - } - - // No config file - prompt for options using shared questions - const answers = await prompter.prompt(argv as CodegenAnswers, codegenQuestions); - // Convert kebab-case CLI args to camelCase for internal use - const camelized = camelizeArgv(answers); + const hasSourceFlags = Boolean( + argv.endpoint || argv['schema-file'] || argv.schemas || argv['api-names'] + ); + const configPath = (argv.config as string | undefined) || + (!hasSourceFlags ? findConfigFile() : undefined); - // Build db config if schemas or apiNames provided - const db = (camelized.schemas || camelized.apiNames) ? { - schemas: camelized.schemas, - apiNames: camelized.apiNames, - } : undefined; + let fileConfig: GraphQLSDKConfigTarget = {}; - const result = await generate({ - endpoint: camelized.endpoint, - schemaFile: camelized.schemaFile, - db, - output: camelized.output, - authorization: camelized.authorization, - reactQuery: camelized.reactQuery, - orm: camelized.orm, - browserCompatible: camelized.browserCompatible, - dryRun: camelized.dryRun, - verbose: camelized.verbose, - }); + if (configPath) { + const loaded = await loadConfigFile(configPath); + if (!loaded.success) { + console.error('x', loaded.error); + process.exit(1); + } + fileConfig = loaded.config as GraphQLSDKConfigTarget; + } + const seeded = seedArgvFromConfig(argv as Record, fileConfig); + const answers = hasResolvedCodegenSource(seeded) + ? seeded + : await prompter.prompt(seeded, codegenQuestions); + const options = buildGenerateOptions(answers, fileConfig); + const result = await generate(options); printResult(result); }; diff --git a/packages/client/package.json b/packages/client/package.json index 57ba56322..0c82f14f1 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -38,7 +38,7 @@ ], "devDependencies": { "@types/pg": "^8.16.0", - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "pg": "^8.17.1" diff --git a/packages/csrf/package.json b/packages/csrf/package.json index 852fef520..9999e727b 100644 --- a/packages/csrf/package.json +++ b/packages/csrf/package.json @@ -21,7 +21,7 @@ }, "devDependencies": { "@types/node": "^20.12.7", - "makage": "^0.1.10", + "makage": "^0.1.12", "ts-node": "^10.9.2" } } diff --git a/packages/csv-to-pg/package.json b/packages/csv-to-pg/package.json index ce03042cd..4660d0d6d 100644 --- a/packages/csv-to-pg/package.json +++ b/packages/csv-to-pg/package.json @@ -33,7 +33,7 @@ }, "devDependencies": { "@types/js-yaml": "^4.0.9", - "makage": "^0.1.10", + "makage": "^0.1.12", "pgsql-parser": "^17.9.11" }, "keywords": [ diff --git a/packages/oauth/package.json b/packages/oauth/package.json index e8ba5a4f3..050e95ef1 100644 --- a/packages/oauth/package.json +++ b/packages/oauth/package.json @@ -33,7 +33,7 @@ }, "devDependencies": { "@types/node": "^20.12.7", - "makage": "^0.1.10", + "makage": "^0.1.12", "ts-node": "^10.9.2" }, "keywords": [ diff --git a/packages/orm/package.json b/packages/orm/package.json index 3a6a589e7..e5051ced0 100644 --- a/packages/orm/package.json +++ b/packages/orm/package.json @@ -33,7 +33,7 @@ }, "devDependencies": { "@types/pg": "^8.16.0", - "makage": "^0.1.10" + "makage": "^0.1.12" }, "keywords": [ "orm", diff --git a/packages/postmaster/package.json b/packages/postmaster/package.json index f53e33ccc..b199607a9 100644 --- a/packages/postmaster/package.json +++ b/packages/postmaster/package.json @@ -34,7 +34,7 @@ "mailgun.js": "^10.2.3" }, "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" }, "keywords": [ "mailgun", diff --git a/packages/query-builder/package.json b/packages/query-builder/package.json index 0ae8671be..ac407e39b 100644 --- a/packages/query-builder/package.json +++ b/packages/query-builder/package.json @@ -36,6 +36,6 @@ "database" ], "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/packages/server-utils/package.json b/packages/server-utils/package.json index 0b290429b..f927445b8 100644 --- a/packages/server-utils/package.json +++ b/packages/server-utils/package.json @@ -38,7 +38,7 @@ "devDependencies": { "@types/cors": "^2.8.17", "@types/express": "^5.0.6", - "makage": "^0.1.10", + "makage": "^0.1.12", "ts-node": "^10.9.2" }, "keywords": [ diff --git a/packages/smtppostmaster/package.json b/packages/smtppostmaster/package.json index 9aa875932..476b81b22 100644 --- a/packages/smtppostmaster/package.json +++ b/packages/smtppostmaster/package.json @@ -38,7 +38,7 @@ "devDependencies": { "@types/nodemailer": "^7.0.5", "@types/smtp-server": "^3.5.12", - "makage": "^0.1.10", + "makage": "^0.1.12", "smtp-server": "^3.14.0", "ts-node": "^10.9.2" }, diff --git a/packages/url-domains/package.json b/packages/url-domains/package.json index df9912ca8..dd2079a8a 100644 --- a/packages/url-domains/package.json +++ b/packages/url-domains/package.json @@ -33,7 +33,7 @@ }, "devDependencies": { "@types/express": "^5.0.6", - "makage": "^0.1.10" + "makage": "^0.1.12" }, "keywords": [] } diff --git a/pgpm/cli/package.json b/pgpm/cli/package.json index d94077b3c..61ce7fb35 100644 --- a/pgpm/cli/package.json +++ b/pgpm/cli/package.json @@ -40,7 +40,7 @@ "@types/semver": "^7.5.8", "@types/shelljs": "^0.8.16", "glob": "^13.0.0", - "makage": "^0.1.10", + "makage": "^0.1.12", "pg": "^8.17.1", "ts-node": "^10.9.2" }, diff --git a/pgpm/core/package.json b/pgpm/core/package.json index 57589c283..b50928021 100644 --- a/pgpm/core/package.json +++ b/pgpm/core/package.json @@ -45,7 +45,7 @@ "@types/pg": "^8.16.0", "copyfiles": "^2.4.1", "inquirerer": "^4.4.0", - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@pgpmjs/env": "workspace:^", diff --git a/pgpm/env/package.json b/pgpm/env/package.json index a390baeeb..a84708df0 100644 --- a/pgpm/env/package.json +++ b/pgpm/env/package.json @@ -41,6 +41,6 @@ "env" ], "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/pgpm/logger/package.json b/pgpm/logger/package.json index 516ae71cd..6591116dd 100644 --- a/pgpm/logger/package.json +++ b/pgpm/logger/package.json @@ -40,6 +40,6 @@ "pgpmjs" ], "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/pgpm/types/package.json b/pgpm/types/package.json index 9d48fd6f4..708f6324e 100644 --- a/pgpm/types/package.json +++ b/pgpm/types/package.json @@ -40,6 +40,6 @@ "migrations" ], "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e00bbd5de..95c7ea774 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,7 @@ settings: packageExtensionsChecksum: sha256-x8B4zkJ4KLRX+yspUWxuggXWlz6zrBLSIh72pNhpPiE= importers: + .: devDependencies: '@jest/test-sequencer': @@ -52,8 +53,8 @@ importers: specifier: ^8.2.3 version: 8.2.4(@types/node@20.19.27)(encoding@0.1.13) makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 prettier: specifier: ^3.8.0 version: 3.8.0 @@ -67,6 +68,40 @@ importers: specifier: ^5.1.6 version: 5.9.3 + examples/codegen-integration: + dependencies: + '@0no-co/graphql.web': + specifier: ^1.2.0 + version: 1.2.0(graphql@15.10.1) + '@tanstack/react-query': + specifier: ^5.90.20 + version: 5.90.20(react@19.2.3) + gql-ast: + specifier: workspace:^ + version: link:../../graphql/gql-ast/dist + graphql: + specifier: 15.10.1 + version: 15.10.1 + react: + specifier: ^19.2.3 + version: 19.2.3 + react-dom: + specifier: ^19.2.3 + version: 19.2.3(react@19.2.3) + devDependencies: + '@constructive-io/graphql-codegen': + specifier: workspace:^ + version: link:../../graphql/codegen/dist + '@constructive-io/graphql-types': + specifier: workspace:^ + version: link:../../graphql/types/dist + tsx: + specifier: ^4.20.3 + version: 4.21.0 + typescript: + specifier: ^5.1.6 + version: 5.9.3 + functions/send-email-link: dependencies: '@constructive-io/knative-job-fn': @@ -77,10 +112,10 @@ importers: version: link:../../packages/postmaster/dist '@launchql/mjml': specifier: 0.1.1 - version: 0.1.1(@babel/core@7.28.6)(encoding@0.1.13)(react-dom@19.2.3(react@19.2.3))(react-is@18.3.1)(react@19.2.3) + version: 0.1.1(@babel/core@7.28.6)(encoding@0.1.13)(react-dom@19.2.3(react@19.2.3))(react-is@19.2.4)(react@19.2.3) '@launchql/styled-email': specifier: 0.1.0 - version: 0.1.0(@babel/core@7.28.6)(encoding@0.1.13)(react-dom@19.2.3(react@19.2.3))(react-is@18.3.1)(react@19.2.3) + version: 0.1.0(@babel/core@7.28.6)(encoding@0.1.13)(react-dom@19.2.3(react@19.2.3))(react-is@19.2.4)(react@19.2.3) '@pgpmjs/env': specifier: workspace:^ version: link:../../pgpm/env/dist @@ -98,8 +133,8 @@ importers: version: link:../../packages/smtppostmaster/dist devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist functions/simple-email: @@ -121,8 +156,8 @@ importers: version: link:../../packages/smtppostmaster/dist devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist graphile/graphile-cache: @@ -147,8 +182,8 @@ importers: specifier: ^8.16.0 version: 8.16.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 nodemon: specifier: ^3.1.10 version: 3.1.11 @@ -197,8 +232,8 @@ importers: specifier: workspace:^ version: link:../graphile-test/dist makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pgsql-test: specifier: workspace:^ version: link:../../postgres/pgsql-test/dist @@ -223,8 +258,8 @@ importers: specifier: 15.10.1 version: 15.10.1 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pgsql-test: specifier: workspace:^ version: link:../../postgres/pgsql-test/dist @@ -258,8 +293,8 @@ importers: specifier: 2.12.6 version: 2.12.6(graphql@15.10.1) makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pgsql-test: specifier: workspace:^ version: link:../../postgres/pgsql-test/dist @@ -281,8 +316,8 @@ importers: specifier: 2.12.6 version: 2.12.6(graphql@15.10.1) makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pgsql-test: specifier: workspace:^ version: link:../../postgres/pgsql-test/dist @@ -316,8 +351,8 @@ importers: specifier: workspace:^ version: link:../graphile-test/dist makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pg: specifier: ^8.17.1 version: 8.17.1 @@ -354,8 +389,8 @@ importers: specifier: 15.10.1 version: 15.10.1 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pg: specifier: ^8.17.1 version: 8.17.1 @@ -392,8 +427,8 @@ importers: specifier: 15.10.1 version: 15.10.1 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pgsql-test: specifier: workspace:^ version: link:../../postgres/pgsql-test/dist @@ -427,8 +462,8 @@ importers: specifier: workspace:^ version: link:../graphile-test/dist makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pgsql-test: specifier: workspace:^ version: link:../../postgres/pgsql-test/dist @@ -450,8 +485,8 @@ importers: specifier: ^8.16.0 version: 8.16.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist graphile/graphile-search-plugin: @@ -476,8 +511,8 @@ importers: specifier: workspace:^ version: link:../graphile-test/dist makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pgsql-test: specifier: workspace:^ version: link:../../postgres/pgsql-test/dist @@ -574,8 +609,8 @@ importers: specifier: ^0.0.41 version: 0.0.41 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 nodemon: specifier: ^3.1.10 version: 3.1.11 @@ -600,8 +635,8 @@ importers: specifier: 2.12.6 version: 2.12.6(graphql@15.10.1) makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pgsql-test: specifier: workspace:^ version: link:../../postgres/pgsql-test/dist @@ -623,8 +658,8 @@ importers: version: 17.9.11 devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 ts-jest: specifier: ^29.4.6 version: 29.4.6(@babel/core@7.28.6)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.6))(jest-util@30.2.0)(jest@30.2.0(@types/node@20.19.27)(ts-node@10.9.2(@types/node@20.19.27)(typescript@5.9.3)))(typescript@5.9.3) @@ -664,8 +699,8 @@ importers: specifier: 2.12.6 version: 2.12.6(graphql@15.10.1) makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist graphile/graphile-upload-plugin: @@ -705,8 +740,8 @@ importers: specifier: ^2.12.6 version: 2.12.6(graphql@15.10.1) makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pgsql-test: specifier: workspace:^ version: link:../../postgres/pgsql-test/dist @@ -826,8 +861,8 @@ importers: version: 4.3.1 devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist graphql/explorer: @@ -888,8 +923,8 @@ importers: specifier: ^8.0.12 version: 8.0.12 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 nodemon: specifier: ^3.1.10 version: 3.1.11 @@ -905,8 +940,8 @@ importers: version: 15.10.1 devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist graphql/playwright-test: @@ -952,8 +987,8 @@ importers: specifier: ^8.16.0 version: 8.16.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist graphql/query: @@ -972,8 +1007,8 @@ importers: version: 3.0.2 devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist graphql/react: @@ -1007,8 +1042,8 @@ importers: specifier: ^19.2.8 version: 19.2.8 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist graphql/server: @@ -1135,8 +1170,8 @@ importers: specifier: workspace:* version: link:../../graphile/graphile-test/dist makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 nodemon: specifier: ^3.1.10 version: 3.1.11 @@ -1191,8 +1226,8 @@ importers: specifier: ^6.0.2 version: 6.0.3 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist graphql/test: @@ -1235,10 +1270,62 @@ importers: specifier: 2.12.6 version: 2.12.6(graphql@15.10.1) makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist + graphql/test-app: + dependencies: + '@0no-co/graphql.web': + specifier: ^1.2.0 + version: 1.2.0(graphql@15.10.1) + '@constructive-io/graphql-types': + specifier: workspace:^ + version: link:../types/dist + '@tanstack/react-query': + specifier: ^5.90.20 + version: 5.90.20(react@19.2.3) + gql-ast: + specifier: workspace:^ + version: link:../gql-ast/dist + graphql: + specifier: 15.10.1 + version: 15.10.1 + react: + specifier: ^19.2.3 + version: 19.2.3 + react-dom: + specifier: ^19.2.3 + version: 19.2.3(react@19.2.3) + devDependencies: + '@constructive-io/graphql-codegen': + specifier: workspace:^ + version: link:../codegen/dist + '@types/react': + specifier: ^19.2.13 + version: 19.2.13 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.13) + '@vitejs/plugin-react': + specifier: ^4.5.2 + version: 4.7.0(vite@6.4.1(@types/node@20.19.27)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + react-test-renderer: + specifier: ^19.2.3 + version: 19.2.3(react@19.2.3) + rollup-plugin-visualizer: + specifier: ^6.0.5 + version: 6.0.5(rollup@4.57.1) + tsx: + specifier: ^4.20.3 + version: 4.21.0 + typescript: + specifier: ^5.8.3 + version: 5.9.3 + vite: + specifier: ^6.3.5 + version: 6.4.1(@types/node@20.19.27)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + graphql/types: dependencies: '@pgpmjs/types': @@ -1258,8 +1345,8 @@ importers: version: 4.14.1 devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist jobs/job-pg: @@ -1275,8 +1362,8 @@ importers: version: 8.17.1 devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist jobs/job-scheduler: @@ -1295,8 +1382,8 @@ importers: version: 1.3.2 devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist jobs/job-utils: @@ -1318,8 +1405,8 @@ importers: version: link:../../postgres/pg-env/dist devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist jobs/job-worker: @@ -1335,8 +1422,8 @@ importers: version: 8.17.1 devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist jobs/knative-job-example: @@ -1346,8 +1433,8 @@ importers: version: link:../knative-job-fn/dist devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist jobs/knative-job-fn: @@ -1363,8 +1450,8 @@ importers: version: 5.2.1 devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist jobs/knative-job-server: @@ -1389,8 +1476,8 @@ importers: version: 8.17.1 devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist jobs/knative-job-service: @@ -1469,8 +1556,8 @@ importers: specifier: ^6.0.3 version: 6.0.3 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pgsql-test: specifier: workspace:^ version: link:../../postgres/pgsql-test/dist @@ -1510,8 +1597,8 @@ importers: specifier: workspace:^ version: link:../../pgpm/core/dist makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pgsql-test: specifier: workspace:^ version: link:../../postgres/pgsql-test/dist @@ -1527,8 +1614,8 @@ importers: specifier: ^20.12.7 version: 20.19.27 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@20.19.27)(typescript@5.9.3) @@ -1613,8 +1700,8 @@ importers: specifier: ^13.0.0 version: 13.0.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pg: specifier: ^8.17.1 version: 8.17.1 @@ -1633,8 +1720,8 @@ importers: specifier: ^8.16.0 version: 8.16.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist packages/csrf: @@ -1643,8 +1730,8 @@ importers: specifier: ^20.12.7 version: 20.19.27 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@20.19.27)(typescript@5.9.3) @@ -1675,8 +1762,8 @@ importers: specifier: ^4.0.9 version: 4.0.9 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pgsql-parser: specifier: ^17.9.11 version: 17.9.11 @@ -1692,8 +1779,8 @@ importers: specifier: ^20.12.7 version: 20.19.27 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@20.19.27)(typescript@5.9.3) @@ -1709,8 +1796,8 @@ importers: specifier: ^8.16.0 version: 8.16.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist packages/postmaster: @@ -1726,15 +1813,15 @@ importers: version: 10.4.0 devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist packages/query-builder: devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist packages/server-utils: @@ -1762,8 +1849,8 @@ importers: specifier: ^5.0.6 version: 5.0.6 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@20.19.27)(typescript@5.9.3) @@ -1788,8 +1875,8 @@ importers: specifier: ^3.5.12 version: 3.5.12 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 smtp-server: specifier: ^3.14.0 version: 3.18.0 @@ -1808,8 +1895,8 @@ importers: specifier: ^5.0.6 version: 5.0.6 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist pgpm/cli: @@ -1885,8 +1972,8 @@ importers: specifier: ^13.0.0 version: 13.0.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pg: specifier: ^8.17.1 version: 8.17.1 @@ -1959,8 +2046,8 @@ importers: specifier: ^4.4.0 version: 4.4.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist pgpm/env: @@ -1973,8 +2060,8 @@ importers: version: 4.3.1 devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist pgpm/logger: @@ -1984,8 +2071,8 @@ importers: version: 0.2.0 devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist pgpm/types: @@ -1995,8 +2082,8 @@ importers: version: link:../../postgres/pg-env/dist devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist postgres/drizzle-orm-test: @@ -2015,8 +2102,8 @@ importers: specifier: ^0.45.1 version: 0.45.1(@types/pg@8.16.0)(pg@8.17.1) makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist postgres/introspectron: @@ -2041,8 +2128,8 @@ importers: specifier: ^8.16.0 version: 8.16.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pgsql-test: specifier: workspace:^ version: link:../pgsql-test/dist @@ -2058,8 +2145,8 @@ importers: version: 0.2.0 devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 pg-proto-parser: specifier: ^1.30.4 version: 1.30.4 @@ -2090,8 +2177,8 @@ importers: specifier: ^8.16.0 version: 8.16.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist postgres/pg-codegen: @@ -2131,15 +2218,15 @@ importers: specifier: ^8.16.0 version: 8.16.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist postgres/pg-env: devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist postgres/pg-query-context: @@ -2152,8 +2239,8 @@ importers: specifier: ^8.16.0 version: 8.16.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist postgres/pg-seed: @@ -2175,8 +2262,8 @@ importers: specifier: ^1.2.5 version: 1.2.5 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist postgres/pgsql-client: @@ -2201,8 +2288,8 @@ importers: specifier: ^8.16.0 version: 8.16.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist postgres/pgsql-seed: @@ -2227,8 +2314,8 @@ importers: specifier: ^8.16.0 version: 8.16.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist postgres/pgsql-test: @@ -2271,8 +2358,8 @@ importers: specifier: ^1.2.5 version: 1.2.5 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist postgres/supabase-test: @@ -2291,8 +2378,8 @@ importers: version: link:../pgsql-test/dist devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist uploads/content-type-stream: @@ -2308,15 +2395,15 @@ importers: version: link:../uuid-hash/dist devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist uploads/etag-hash: devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist uploads/etag-stream: @@ -2329,8 +2416,8 @@ importers: specifier: ^13.0.0 version: 13.0.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist uploads/mime-bytes: @@ -2339,8 +2426,8 @@ importers: specifier: ^13.0.0 version: 13.0.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist uploads/s3-streamer: @@ -2368,8 +2455,8 @@ importers: specifier: ^13.0.0 version: 13.0.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist uploads/s3-utils: @@ -2385,8 +2472,8 @@ importers: specifier: ^18.19.69 version: 18.19.130 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist uploads/stream-to-etag: @@ -2399,8 +2486,8 @@ importers: specifier: ^13.0.0 version: 13.0.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist uploads/upload-names: @@ -2409,15 +2496,15 @@ importers: specifier: ^13.0.0 version: 13.0.0 makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist uploads/uuid-hash: devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist uploads/uuid-stream: @@ -2427,16 +2514,14 @@ importers: version: link:../uuid-hash/dist devDependencies: makage: - specifier: ^0.1.10 - version: 0.1.10 + specifier: ^0.1.12 + version: 0.1.12 publishDirectory: dist packages: + '@0no-co/graphql.web@1.2.0': - resolution: - { - integrity: sha512-/1iHy9TTr63gE1YcR5idjx8UREz1s0kFhydf3bBLCXyqjhkIc6igAzTOx3zPifCwFR87tsh/4Pa9cNts6d2otw==, - } + resolution: {integrity: sha512-/1iHy9TTr63gE1YcR5idjx8UREz1s0kFhydf3bBLCXyqjhkIc6igAzTOx3zPifCwFR87tsh/4Pa9cNts6d2otw==} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 peerDependenciesMeta: @@ -2444,399 +2529,228 @@ packages: optional: true '@aws-crypto/crc32@5.2.0': - resolution: - { - integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==, - } - engines: { node: '>=16.0.0' } + resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} + engines: {node: '>=16.0.0'} '@aws-crypto/crc32c@5.2.0': - resolution: - { - integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==, - } + resolution: {integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==} '@aws-crypto/sha1-browser@5.2.0': - resolution: - { - integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==, - } + resolution: {integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==} '@aws-crypto/sha256-browser@5.2.0': - resolution: - { - integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==, - } + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} '@aws-crypto/sha256-js@5.2.0': - resolution: - { - integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==, - } - engines: { node: '>=16.0.0' } + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} '@aws-crypto/supports-web-crypto@5.2.0': - resolution: - { - integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==, - } + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} '@aws-crypto/util@5.2.0': - resolution: - { - integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==, - } + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} '@aws-sdk/client-s3@3.971.0': - resolution: - { - integrity: sha512-BBUne390fKa4C4QvZlUZ5gKcu+Uyid4IyQ20N4jl0vS7SK2xpfXlJcgKqPW5ts6kx6hWTQBk6sH5Lf12RvuJxg==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-BBUne390fKa4C4QvZlUZ5gKcu+Uyid4IyQ20N4jl0vS7SK2xpfXlJcgKqPW5ts6kx6hWTQBk6sH5Lf12RvuJxg==} + engines: {node: '>=20.0.0'} '@aws-sdk/client-sesv2@3.969.0': - resolution: - { - integrity: sha512-YnBJRtueyNAeKJvRNBVAeH9fh5X8KmMa4fp1Zn1Hex0G5bRKm0aUdS4i+p5cOIpCyBV9hyLGGkaCBDC4Han7aw==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-YnBJRtueyNAeKJvRNBVAeH9fh5X8KmMa4fp1Zn1Hex0G5bRKm0aUdS4i+p5cOIpCyBV9hyLGGkaCBDC4Han7aw==} + engines: {node: '>=20.0.0'} '@aws-sdk/client-sso@3.969.0': - resolution: - { - integrity: sha512-Qn0Uz6o15q2S+1E6OpwRKmaAMoT4LktEn+Oibk28qb2Mne+emaDawhZXahOJb/wFw5lN2FEH7XoiSNenNNUmCw==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-Qn0Uz6o15q2S+1E6OpwRKmaAMoT4LktEn+Oibk28qb2Mne+emaDawhZXahOJb/wFw5lN2FEH7XoiSNenNNUmCw==} + engines: {node: '>=20.0.0'} '@aws-sdk/client-sso@3.971.0': - resolution: - { - integrity: sha512-Xx+w6DQqJxDdymYyIxyKJnRzPvVJ4e/Aw0czO7aC9L/iraaV7AG8QtRe93OGW6aoHSh72CIiinnpJJfLsQqP4g==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-Xx+w6DQqJxDdymYyIxyKJnRzPvVJ4e/Aw0czO7aC9L/iraaV7AG8QtRe93OGW6aoHSh72CIiinnpJJfLsQqP4g==} + engines: {node: '>=20.0.0'} '@aws-sdk/core@3.969.0': - resolution: - { - integrity: sha512-qqmQt4z5rEK1OYVkVkboWgy/58CC5QaQ7oy0tvLe3iri/mfZbgJkA+pkwQyRP827DfCBZ3W7Ki9iwSa+B2U7uQ==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-qqmQt4z5rEK1OYVkVkboWgy/58CC5QaQ7oy0tvLe3iri/mfZbgJkA+pkwQyRP827DfCBZ3W7Ki9iwSa+B2U7uQ==} + engines: {node: '>=20.0.0'} '@aws-sdk/core@3.970.0': - resolution: - { - integrity: sha512-klpzObldOq8HXzDjDlY6K8rMhYZU6mXRz6P9F9N+tWnjoYFfeBMra8wYApydElTUYQKP1O7RLHwH1OKFfKcqIA==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-klpzObldOq8HXzDjDlY6K8rMhYZU6mXRz6P9F9N+tWnjoYFfeBMra8wYApydElTUYQKP1O7RLHwH1OKFfKcqIA==} + engines: {node: '>=20.0.0'} '@aws-sdk/crc64-nvme@3.969.0': - resolution: - { - integrity: sha512-IGNkP54HD3uuLnrPCYsv3ZD478UYq+9WwKrIVJ9Pdi3hxPg8562CH3ZHf8hEgfePN31P9Kj+Zu9kq2Qcjjt61A==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-IGNkP54HD3uuLnrPCYsv3ZD478UYq+9WwKrIVJ9Pdi3hxPg8562CH3ZHf8hEgfePN31P9Kj+Zu9kq2Qcjjt61A==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-env@3.969.0': - resolution: - { - integrity: sha512-yS96heH5XDUqS3qQNcdObKKMOqZaivuNInMVRpRli48aXW8fX1M3fY67K/Onlqa3Wxu6WfDc3ZGF52SywdLvbg==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-yS96heH5XDUqS3qQNcdObKKMOqZaivuNInMVRpRli48aXW8fX1M3fY67K/Onlqa3Wxu6WfDc3ZGF52SywdLvbg==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-env@3.970.0': - resolution: - { - integrity: sha512-rtVzXzEtAfZBfh+lq3DAvRar4c3jyptweOAJR2DweyXx71QSMY+O879hjpMwES7jl07a3O1zlnFIDo4KP/96kQ==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-rtVzXzEtAfZBfh+lq3DAvRar4c3jyptweOAJR2DweyXx71QSMY+O879hjpMwES7jl07a3O1zlnFIDo4KP/96kQ==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-http@3.969.0': - resolution: - { - integrity: sha512-QCEFxBiUYFUW5VG6k8jKhT4luZndpC7uUY4u1olwt+OnJrl3N2yC7oS34isVBa3ioXZ4A0YagbXTa/3mXUhlAA==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-QCEFxBiUYFUW5VG6k8jKhT4luZndpC7uUY4u1olwt+OnJrl3N2yC7oS34isVBa3ioXZ4A0YagbXTa/3mXUhlAA==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-http@3.970.0': - resolution: - { - integrity: sha512-CjDbWL7JxjLc9ZxQilMusWSw05yRvUJKRpz59IxDpWUnSMHC9JMMUUkOy5Izk8UAtzi6gupRWArp4NG4labt9Q==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-CjDbWL7JxjLc9ZxQilMusWSw05yRvUJKRpz59IxDpWUnSMHC9JMMUUkOy5Izk8UAtzi6gupRWArp4NG4labt9Q==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-ini@3.969.0': - resolution: - { - integrity: sha512-lsXyTDkUrZPxjr0XruZrqdcHY9zHcIuoY3TOCQEm23VTc8Np2BenTtjGAIexkL3ar69K4u3FVLQroLpmFxeXqA==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-lsXyTDkUrZPxjr0XruZrqdcHY9zHcIuoY3TOCQEm23VTc8Np2BenTtjGAIexkL3ar69K4u3FVLQroLpmFxeXqA==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-ini@3.971.0': - resolution: - { - integrity: sha512-c0TGJG4xyfTZz3SInXfGU8i5iOFRrLmy4Bo7lMyH+IpngohYMYGYl61omXqf2zdwMbDv+YJ9AviQTcCaEUKi8w==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-c0TGJG4xyfTZz3SInXfGU8i5iOFRrLmy4Bo7lMyH+IpngohYMYGYl61omXqf2zdwMbDv+YJ9AviQTcCaEUKi8w==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-login@3.969.0': - resolution: - { - integrity: sha512-bIRFDf54qIUFFLTZNYt40d6EseNeK9w80dHEs7BVEAWoS23c9+MSqkdg/LJBBK9Kgy01vRmjiedfBZN+jGypLw==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-bIRFDf54qIUFFLTZNYt40d6EseNeK9w80dHEs7BVEAWoS23c9+MSqkdg/LJBBK9Kgy01vRmjiedfBZN+jGypLw==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-login@3.971.0': - resolution: - { - integrity: sha512-yhbzmDOsk0RXD3rTPhZra4AWVnVAC4nFWbTp+sUty1hrOPurUmhuz8bjpLqYTHGnlMbJp+UqkQONhS2+2LzW2g==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-yhbzmDOsk0RXD3rTPhZra4AWVnVAC4nFWbTp+sUty1hrOPurUmhuz8bjpLqYTHGnlMbJp+UqkQONhS2+2LzW2g==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-node@3.969.0': - resolution: - { - integrity: sha512-lImMjcy/5SGDIBk7PFJCqFO4rFuapKCvo1z2PidD3Cbz2D7wsJnyqUNQIp5Ix0Xc3/uAYG9zXI9kgaMf1dspIQ==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-lImMjcy/5SGDIBk7PFJCqFO4rFuapKCvo1z2PidD3Cbz2D7wsJnyqUNQIp5Ix0Xc3/uAYG9zXI9kgaMf1dspIQ==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-node@3.971.0': - resolution: - { - integrity: sha512-epUJBAKivtJqalnEBRsYIULKYV063o/5mXNJshZfyvkAgNIzc27CmmKRXTN4zaNOZg8g/UprFp25BGsi19x3nQ==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-epUJBAKivtJqalnEBRsYIULKYV063o/5mXNJshZfyvkAgNIzc27CmmKRXTN4zaNOZg8g/UprFp25BGsi19x3nQ==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-process@3.969.0': - resolution: - { - integrity: sha512-2qQkM0rwd8Hl9nIHtUaqT8Z/djrulovqx/wBHsbRKaISwc2fiT3De1Lk1jx34Jzrz/dTHAMJJi+cML1N4Lk3kw==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-2qQkM0rwd8Hl9nIHtUaqT8Z/djrulovqx/wBHsbRKaISwc2fiT3De1Lk1jx34Jzrz/dTHAMJJi+cML1N4Lk3kw==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-process@3.970.0': - resolution: - { - integrity: sha512-0XeT8OaT9iMA62DFV9+m6mZfJhrD0WNKf4IvsIpj2Z7XbaYfz3CoDDvNoALf3rPY9NzyMHgDxOspmqdvXP00mw==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-0XeT8OaT9iMA62DFV9+m6mZfJhrD0WNKf4IvsIpj2Z7XbaYfz3CoDDvNoALf3rPY9NzyMHgDxOspmqdvXP00mw==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-sso@3.969.0': - resolution: - { - integrity: sha512-JHqXw9Ct3dtZB86/zGFJYWyodr961GyIrqTBhV0brrZFPvcinM9abDSK58jt6GNBM2lqfMCvXL6I4ahNsMdkrg==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-JHqXw9Ct3dtZB86/zGFJYWyodr961GyIrqTBhV0brrZFPvcinM9abDSK58jt6GNBM2lqfMCvXL6I4ahNsMdkrg==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-sso@3.971.0': - resolution: - { - integrity: sha512-dY0hMQ7dLVPQNJ8GyqXADxa9w5wNfmukgQniLxGVn+dMRx3YLViMp5ZpTSQpFhCWNF0oKQrYAI5cHhUJU1hETw==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-dY0hMQ7dLVPQNJ8GyqXADxa9w5wNfmukgQniLxGVn+dMRx3YLViMp5ZpTSQpFhCWNF0oKQrYAI5cHhUJU1hETw==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-web-identity@3.969.0': - resolution: - { - integrity: sha512-mKCZtqrs3ts3YmIjT4NFlYgT2Oe6syW0nX5m2l7iyrFrLXw26Zo3rx29DjGzycPdJHZZvsIy5y6yqChDuF65ng==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-mKCZtqrs3ts3YmIjT4NFlYgT2Oe6syW0nX5m2l7iyrFrLXw26Zo3rx29DjGzycPdJHZZvsIy5y6yqChDuF65ng==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-web-identity@3.971.0': - resolution: - { - integrity: sha512-F1AwfNLr7H52T640LNON/h34YDiMuIqW/ZreGzhRR6vnFGaSPtNSKAKB2ssAMkLM8EVg8MjEAYD3NCUiEo+t/w==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-F1AwfNLr7H52T640LNON/h34YDiMuIqW/ZreGzhRR6vnFGaSPtNSKAKB2ssAMkLM8EVg8MjEAYD3NCUiEo+t/w==} + engines: {node: '>=20.0.0'} '@aws-sdk/lib-storage@3.958.0': - resolution: - { - integrity: sha512-cd8CTiJ165ep2DKTc2PHHhVCxDn3byv10BXMGn+lkDY3KwMoatcgZ1uhFWCBuJvsCUnSExqGouJN/Q0qgjkWtg==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-cd8CTiJ165ep2DKTc2PHHhVCxDn3byv10BXMGn+lkDY3KwMoatcgZ1uhFWCBuJvsCUnSExqGouJN/Q0qgjkWtg==} + engines: {node: '>=18.0.0'} peerDependencies: '@aws-sdk/client-s3': ^3.958.0 '@aws-sdk/middleware-bucket-endpoint@3.969.0': - resolution: - { - integrity: sha512-MlbrlixtkTVhYhoasblKOkr7n2yydvUZjjxTnBhIuHmkyBS1619oGnTfq/uLeGYb4NYXdeQ5OYcqsRGvmWSuTw==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-MlbrlixtkTVhYhoasblKOkr7n2yydvUZjjxTnBhIuHmkyBS1619oGnTfq/uLeGYb4NYXdeQ5OYcqsRGvmWSuTw==} + engines: {node: '>=20.0.0'} '@aws-sdk/middleware-expect-continue@3.969.0': - resolution: - { - integrity: sha512-qXygzSi8osok7tH9oeuS3HoKw6jRfbvg5Me/X5RlHOvSSqQz8c5O9f3MjUApaCUSwbAU92KrbZWasw2PKiaVHg==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-qXygzSi8osok7tH9oeuS3HoKw6jRfbvg5Me/X5RlHOvSSqQz8c5O9f3MjUApaCUSwbAU92KrbZWasw2PKiaVHg==} + engines: {node: '>=20.0.0'} '@aws-sdk/middleware-flexible-checksums@3.971.0': - resolution: - { - integrity: sha512-+hGUDUxeIw8s2kkjfeXym0XZxdh0cqkHkDpEanWYdS1gnWkIR+gf9u/DKbKqGHXILPaqHXhWpLTQTVlaB4sI7Q==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-+hGUDUxeIw8s2kkjfeXym0XZxdh0cqkHkDpEanWYdS1gnWkIR+gf9u/DKbKqGHXILPaqHXhWpLTQTVlaB4sI7Q==} + engines: {node: '>=20.0.0'} '@aws-sdk/middleware-host-header@3.969.0': - resolution: - { - integrity: sha512-AWa4rVsAfBR4xqm7pybQ8sUNJYnjyP/bJjfAw34qPuh3M9XrfGbAHG0aiAfQGrBnmS28jlO6Kz69o+c6PRw1dw==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-AWa4rVsAfBR4xqm7pybQ8sUNJYnjyP/bJjfAw34qPuh3M9XrfGbAHG0aiAfQGrBnmS28jlO6Kz69o+c6PRw1dw==} + engines: {node: '>=20.0.0'} '@aws-sdk/middleware-location-constraint@3.969.0': - resolution: - { - integrity: sha512-zH7pDfMLG/C4GWMOpvJEoYcSpj7XsNP9+irlgqwi667sUQ6doHQJ3yyDut3yiTk0maq1VgmriPFELyI9lrvH/g==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-zH7pDfMLG/C4GWMOpvJEoYcSpj7XsNP9+irlgqwi667sUQ6doHQJ3yyDut3yiTk0maq1VgmriPFELyI9lrvH/g==} + engines: {node: '>=20.0.0'} '@aws-sdk/middleware-logger@3.969.0': - resolution: - { - integrity: sha512-xwrxfip7Y2iTtCMJ+iifN1E1XMOuhxIHY9DreMCvgdl4r7+48x2S1bCYPWH3eNY85/7CapBWdJ8cerpEl12sQQ==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-xwrxfip7Y2iTtCMJ+iifN1E1XMOuhxIHY9DreMCvgdl4r7+48x2S1bCYPWH3eNY85/7CapBWdJ8cerpEl12sQQ==} + engines: {node: '>=20.0.0'} '@aws-sdk/middleware-recursion-detection@3.969.0': - resolution: - { - integrity: sha512-2r3PuNquU3CcS1Am4vn/KHFwLi8QFjMdA/R+CRDXT4AFO/0qxevF/YStW3gAKntQIgWgQV8ZdEtKAoJvLI4UWg==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-2r3PuNquU3CcS1Am4vn/KHFwLi8QFjMdA/R+CRDXT4AFO/0qxevF/YStW3gAKntQIgWgQV8ZdEtKAoJvLI4UWg==} + engines: {node: '>=20.0.0'} '@aws-sdk/middleware-sdk-s3@3.969.0': - resolution: - { - integrity: sha512-xjcyZrbtvVaqkmjkhmqX+16Wf7zFVS/cYnNFu/JyG6ekkIxSXEAjptNwSEDzlAiLzf0Hf6dYj5erLZYGa40eWg==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-xjcyZrbtvVaqkmjkhmqX+16Wf7zFVS/cYnNFu/JyG6ekkIxSXEAjptNwSEDzlAiLzf0Hf6dYj5erLZYGa40eWg==} + engines: {node: '>=20.0.0'} '@aws-sdk/middleware-sdk-s3@3.970.0': - resolution: - { - integrity: sha512-v/Y5F1lbFFY7vMeG5yYxuhnn0CAshz6KMxkz1pDyPxejNE9HtA0w8R6OTBh/bVdIm44QpjhbI7qeLdOE/PLzXQ==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-v/Y5F1lbFFY7vMeG5yYxuhnn0CAshz6KMxkz1pDyPxejNE9HtA0w8R6OTBh/bVdIm44QpjhbI7qeLdOE/PLzXQ==} + engines: {node: '>=20.0.0'} '@aws-sdk/middleware-ssec@3.971.0': - resolution: - { - integrity: sha512-QGVhvRveYG64ZhnS/b971PxXM6N2NU79Fxck4EfQ7am8v1Br0ctoeDDAn9nXNblLGw87we9Z65F7hMxxiFHd3w==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-QGVhvRveYG64ZhnS/b971PxXM6N2NU79Fxck4EfQ7am8v1Br0ctoeDDAn9nXNblLGw87we9Z65F7hMxxiFHd3w==} + engines: {node: '>=20.0.0'} '@aws-sdk/middleware-user-agent@3.969.0': - resolution: - { - integrity: sha512-Y6WkW8QQ2X9jG9HNBWyzp5KlJOCtLqX8VIvGLoGc2wXdZH7dgOy62uFhkfnHbgfiel6fkNYaycjGx/yyxi0JLQ==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-Y6WkW8QQ2X9jG9HNBWyzp5KlJOCtLqX8VIvGLoGc2wXdZH7dgOy62uFhkfnHbgfiel6fkNYaycjGx/yyxi0JLQ==} + engines: {node: '>=20.0.0'} '@aws-sdk/middleware-user-agent@3.970.0': - resolution: - { - integrity: sha512-dnSJGGUGSFGEX2NzvjwSefH+hmZQ347AwbLhAsi0cdnISSge+pcGfOFrJt2XfBIypwFe27chQhlfuf/gWdzpZg==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-dnSJGGUGSFGEX2NzvjwSefH+hmZQ347AwbLhAsi0cdnISSge+pcGfOFrJt2XfBIypwFe27chQhlfuf/gWdzpZg==} + engines: {node: '>=20.0.0'} '@aws-sdk/nested-clients@3.969.0': - resolution: - { - integrity: sha512-MJrejgODxVYZjQjSpPLJkVuxnbrue1x1R8+as3anT5V/wk9Qc/Pf5B1IFjM3Ak6uOtzuRYNY4auOvcg4U8twDA==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-MJrejgODxVYZjQjSpPLJkVuxnbrue1x1R8+as3anT5V/wk9Qc/Pf5B1IFjM3Ak6uOtzuRYNY4auOvcg4U8twDA==} + engines: {node: '>=20.0.0'} '@aws-sdk/nested-clients@3.971.0': - resolution: - { - integrity: sha512-TWaILL8GyYlhGrxxnmbkazM4QsXatwQgoWUvo251FXmUOsiXDFDVX3hoGIfB3CaJhV2pJPfebHUNJtY6TjZ11g==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-TWaILL8GyYlhGrxxnmbkazM4QsXatwQgoWUvo251FXmUOsiXDFDVX3hoGIfB3CaJhV2pJPfebHUNJtY6TjZ11g==} + engines: {node: '>=20.0.0'} '@aws-sdk/region-config-resolver@3.969.0': - resolution: - { - integrity: sha512-scj9OXqKpcjJ4jsFLtqYWz3IaNvNOQTFFvEY8XMJXTv+3qF5I7/x9SJtKzTRJEBF3spjzBUYPtGFbs9sj4fisQ==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-scj9OXqKpcjJ4jsFLtqYWz3IaNvNOQTFFvEY8XMJXTv+3qF5I7/x9SJtKzTRJEBF3spjzBUYPtGFbs9sj4fisQ==} + engines: {node: '>=20.0.0'} '@aws-sdk/signature-v4-multi-region@3.969.0': - resolution: - { - integrity: sha512-pv8BEQOlUzK+ww8ZfXZOnDzLfPO5+O7puBFtU1fE8CdCAQ/RP/B1XY3hxzW9Xs0dax7graYKnY8wd8ooYy7vBw==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-pv8BEQOlUzK+ww8ZfXZOnDzLfPO5+O7puBFtU1fE8CdCAQ/RP/B1XY3hxzW9Xs0dax7graYKnY8wd8ooYy7vBw==} + engines: {node: '>=20.0.0'} '@aws-sdk/signature-v4-multi-region@3.970.0': - resolution: - { - integrity: sha512-z3syXfuK/x/IsKf/AeYmgc2NT7fcJ+3fHaGO+fkghkV9WEba3fPyOwtTBX4KpFMNb2t50zDGZwbzW1/5ighcUQ==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-z3syXfuK/x/IsKf/AeYmgc2NT7fcJ+3fHaGO+fkghkV9WEba3fPyOwtTBX4KpFMNb2t50zDGZwbzW1/5ighcUQ==} + engines: {node: '>=20.0.0'} '@aws-sdk/token-providers@3.969.0': - resolution: - { - integrity: sha512-ucs6QczPkvGinbGmhMlPCQnagGJ+xsM6itsSWlJzxo9YsP6jR75cBU8pRdaM7nEbtCDnrUHf8W9g3D2Hd9mgVA==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-ucs6QczPkvGinbGmhMlPCQnagGJ+xsM6itsSWlJzxo9YsP6jR75cBU8pRdaM7nEbtCDnrUHf8W9g3D2Hd9mgVA==} + engines: {node: '>=20.0.0'} '@aws-sdk/token-providers@3.971.0': - resolution: - { - integrity: sha512-4hKGWZbmuDdONMJV0HJ+9jwTDb0zLfKxcCLx2GEnBY31Gt9GeyIQ+DZ97Bb++0voawj6pnZToFikXTyrEq2x+w==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-4hKGWZbmuDdONMJV0HJ+9jwTDb0zLfKxcCLx2GEnBY31Gt9GeyIQ+DZ97Bb++0voawj6pnZToFikXTyrEq2x+w==} + engines: {node: '>=20.0.0'} '@aws-sdk/types@3.969.0': - resolution: - { - integrity: sha512-7IIzM5TdiXn+VtgPdVLjmE6uUBUtnga0f4RiSEI1WW10RPuNvZ9U+pL3SwDiRDAdoGrOF9tSLJOFZmfuwYuVYQ==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-7IIzM5TdiXn+VtgPdVLjmE6uUBUtnga0f4RiSEI1WW10RPuNvZ9U+pL3SwDiRDAdoGrOF9tSLJOFZmfuwYuVYQ==} + engines: {node: '>=20.0.0'} '@aws-sdk/util-arn-parser@3.968.0': - resolution: - { - integrity: sha512-gqqvYcitIIM2K4lrDX9de9YvOfXBcVdxfT/iLnvHJd4YHvSXlt+gs+AsL4FfPCxG4IG9A+FyulP9Sb1MEA75vw==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-gqqvYcitIIM2K4lrDX9de9YvOfXBcVdxfT/iLnvHJd4YHvSXlt+gs+AsL4FfPCxG4IG9A+FyulP9Sb1MEA75vw==} + engines: {node: '>=20.0.0'} '@aws-sdk/util-endpoints@3.969.0': - resolution: - { - integrity: sha512-H2x2UwYiA1pHg40jE+OCSc668W9GXRShTiCWy1UPKtZKREbQ63Mgd7NAj+bEMsZUSCdHywqmSsLqKM9IcqQ3Bg==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-H2x2UwYiA1pHg40jE+OCSc668W9GXRShTiCWy1UPKtZKREbQ63Mgd7NAj+bEMsZUSCdHywqmSsLqKM9IcqQ3Bg==} + engines: {node: '>=20.0.0'} '@aws-sdk/util-endpoints@3.970.0': - resolution: - { - integrity: sha512-TZNZqFcMUtjvhZoZRtpEGQAdULYiy6rcGiXAbLU7e9LSpIYlRqpLa207oMNfgbzlL2PnHko+eVg8rajDiSOYCg==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-TZNZqFcMUtjvhZoZRtpEGQAdULYiy6rcGiXAbLU7e9LSpIYlRqpLa207oMNfgbzlL2PnHko+eVg8rajDiSOYCg==} + engines: {node: '>=20.0.0'} '@aws-sdk/util-locate-window@3.965.2': - resolution: - { - integrity: sha512-qKgO7wAYsXzhwCHhdbaKFyxd83Fgs8/1Ka+jjSPrv2Ll7mB55Wbwlo0kkfMLh993/yEc8aoDIAc1Fz9h4Spi4Q==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-qKgO7wAYsXzhwCHhdbaKFyxd83Fgs8/1Ka+jjSPrv2Ll7mB55Wbwlo0kkfMLh993/yEc8aoDIAc1Fz9h4Spi4Q==} + engines: {node: '>=20.0.0'} '@aws-sdk/util-user-agent-browser@3.969.0': - resolution: - { - integrity: sha512-bpJGjuKmFr0rA6UKUCmN8D19HQFMLXMx5hKBXqBlPFdalMhxJSjcxzX9DbQh0Fn6bJtxCguFmRGOBdQqNOt49g==, - } + resolution: {integrity: sha512-bpJGjuKmFr0rA6UKUCmN8D19HQFMLXMx5hKBXqBlPFdalMhxJSjcxzX9DbQh0Fn6bJtxCguFmRGOBdQqNOt49g==} '@aws-sdk/util-user-agent-node@3.969.0': - resolution: - { - integrity: sha512-D11ZuXNXdUMv8XTthMx+LPzkYNQAeQ68FnCTGnFLgLpnR8hVTeZMBBKjQ77wYGzWDk/csHKdCy697gU1On5KjA==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-D11ZuXNXdUMv8XTthMx+LPzkYNQAeQ68FnCTGnFLgLpnR8hVTeZMBBKjQ77wYGzWDk/csHKdCy697gU1On5KjA==} + engines: {node: '>=20.0.0'} peerDependencies: aws-crt: '>=1.0.0' peerDependenciesMeta: @@ -2844,11 +2758,8 @@ packages: optional: true '@aws-sdk/util-user-agent-node@3.971.0': - resolution: - { - integrity: sha512-Eygjo9mFzQYjbGY3MYO6CsIhnTwAMd3WmuFalCykqEmj2r5zf0leWrhPaqvA5P68V5JdGfPYgj7vhNOd6CtRBQ==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-Eygjo9mFzQYjbGY3MYO6CsIhnTwAMd3WmuFalCykqEmj2r5zf0leWrhPaqvA5P68V5JdGfPYgj7vhNOd6CtRBQ==} + engines: {node: '>=20.0.0'} peerDependencies: aws-crt: '>=1.0.0' peerDependenciesMeta: @@ -2856,798 +2767,657 @@ packages: optional: true '@aws-sdk/xml-builder@3.969.0': - resolution: - { - integrity: sha512-BSe4Lx/qdRQQdX8cSSI7Et20vqBspzAjBy8ZmXVoyLkol3y4sXBXzn+BiLtR+oh60ExQn6o2DU4QjdOZbXaKIQ==, - } - engines: { node: '>=20.0.0' } + resolution: {integrity: sha512-BSe4Lx/qdRQQdX8cSSI7Et20vqBspzAjBy8ZmXVoyLkol3y4sXBXzn+BiLtR+oh60ExQn6o2DU4QjdOZbXaKIQ==} + engines: {node: '>=20.0.0'} '@aws/lambda-invoke-store@0.2.3': - resolution: - { - integrity: sha512-oLvsaPMTBejkkmHhjf09xTgk71mOqyr/409NKhRIL08If7AhVfUsJhVsx386uJaqNd42v9kWamQ9lFbkoC2dYw==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-oLvsaPMTBejkkmHhjf09xTgk71mOqyr/409NKhRIL08If7AhVfUsJhVsx386uJaqNd42v9kWamQ9lFbkoC2dYw==} + engines: {node: '>=18.0.0'} '@babel/code-frame@7.27.1': - resolution: - { - integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} '@babel/code-frame@7.28.6': - resolution: - { - integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} + engines: {node: '>=6.9.0'} '@babel/compat-data@7.28.6': - resolution: - { - integrity: sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==} + engines: {node: '>=6.9.0'} '@babel/core@7.28.6': - resolution: - { - integrity: sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==} + engines: {node: '>=6.9.0'} '@babel/generator@7.28.6': - resolution: - { - integrity: sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==} + engines: {node: '>=6.9.0'} '@babel/helper-annotate-as-pure@7.27.3': - resolution: - { - integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + engines: {node: '>=6.9.0'} '@babel/helper-compilation-targets@7.28.6': - resolution: - { - integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} '@babel/helper-globals@7.28.0': - resolution: - { - integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} '@babel/helper-module-imports@7.27.1': - resolution: - { - integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} '@babel/helper-module-imports@7.28.6': - resolution: - { - integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} '@babel/helper-module-transforms@7.28.6': - resolution: - { - integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 '@babel/helper-plugin-utils@7.27.1': - resolution: - { - integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + engines: {node: '>=6.9.0'} '@babel/helper-plugin-utils@7.28.6': - resolution: - { - integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + engines: {node: '>=6.9.0'} '@babel/helper-string-parser@7.27.1': - resolution: - { - integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} '@babel/helper-validator-identifier@7.28.5': - resolution: - { - integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} '@babel/helper-validator-option@7.27.1': - resolution: - { - integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} '@babel/helpers@7.28.6': - resolution: - { - integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + engines: {node: '>=6.9.0'} '@babel/parser@7.28.6': - resolution: - { - integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==, - } - engines: { node: '>=6.0.0' } + resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==} + engines: {node: '>=6.0.0'} hasBin: true '@babel/plugin-syntax-async-generators@7.8.4': - resolution: - { - integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==, - } + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-syntax-bigint@7.8.3': - resolution: - { - integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==, - } + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-syntax-class-properties@7.12.13': - resolution: - { - integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==, - } + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-syntax-class-static-block@7.14.5': - resolution: - { - integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-syntax-import-attributes@7.28.6': - resolution: - { - integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-syntax-import-meta@7.10.4': - resolution: - { - integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==, - } + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-syntax-json-strings@7.8.3': - resolution: - { - integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==, - } + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-syntax-jsx@7.27.1': - resolution: - { - integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-syntax-jsx@7.28.6': - resolution: - { - integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-syntax-logical-assignment-operators@7.10.4': - resolution: - { - integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==, - } + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': - resolution: - { - integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==, - } + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-syntax-numeric-separator@7.10.4': - resolution: - { - integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==, - } + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-syntax-object-rest-spread@7.8.3': - resolution: - { - integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==, - } + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-syntax-optional-catch-binding@7.8.3': - resolution: - { - integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==, - } + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-syntax-optional-chaining@7.8.3': - resolution: - { - integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==, - } + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-syntax-private-property-in-object@7.14.5': - resolution: - { - integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-syntax-top-level-await@7.14.5': - resolution: - { - integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-syntax-typescript@7.28.6': - resolution: - { - integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 '@babel/runtime-corejs3@7.28.4': - resolution: - { - integrity: sha512-h7iEYiW4HebClDEhtvFObtPmIvrd1SSfpI9EhOeKk4CtIK/ngBWFpuhCzhdmRKtg71ylcue+9I6dv54XYO1epQ==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-h7iEYiW4HebClDEhtvFObtPmIvrd1SSfpI9EhOeKk4CtIK/ngBWFpuhCzhdmRKtg71ylcue+9I6dv54XYO1epQ==} + engines: {node: '>=6.9.0'} '@babel/runtime@7.28.4': - resolution: - { - integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + engines: {node: '>=6.9.0'} '@babel/template@7.27.2': - resolution: - { - integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} '@babel/template@7.28.6': - resolution: - { - integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} '@babel/traverse@7.28.5': - resolution: - { - integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + engines: {node: '>=6.9.0'} '@babel/traverse@7.28.6': - resolution: - { - integrity: sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==} + engines: {node: '>=6.9.0'} '@babel/types@7.28.5': - resolution: - { - integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} '@babel/types@7.28.6': - resolution: - { - integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} + engines: {node: '>=6.9.0'} '@bcoe/v8-coverage@0.2.3': - resolution: - { - integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==, - } + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} '@cspotcode/source-map-support@0.8.1': - resolution: - { - integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==, - } - engines: { node: '>=12' } + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} '@emnapi/core@1.7.1': - resolution: - { - integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==, - } + resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} '@emnapi/core@1.8.1': - resolution: - { - integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==, - } + resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} '@emnapi/runtime@1.7.1': - resolution: - { - integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==, - } + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} '@emnapi/runtime@1.8.1': - resolution: - { - integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==, - } + resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} '@emnapi/wasi-threads@1.1.0': - resolution: - { - integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==, - } + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} '@emotion/is-prop-valid@1.4.0': - resolution: - { - integrity: sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==, - } + resolution: {integrity: sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==} '@emotion/memoize@0.9.0': - resolution: - { - integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==, - } + resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} '@emotion/stylis@0.8.5': - resolution: - { - integrity: sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==, - } + resolution: {integrity: sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==} '@emotion/unitless@0.7.5': - resolution: - { - integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==, - } + resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] '@esbuild/aix-ppc64@0.27.2': - resolution: - { - integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} + engines: {node: '>=18'} cpu: [ppc64] os: [aix] + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm64@0.27.2': - resolution: - { - integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} + engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-arm@0.27.2': - resolution: - { - integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} + engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/android-x64@0.27.2': - resolution: - { - integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} + engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-arm64@0.27.2': - resolution: - { - integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/darwin-x64@0.27.2': - resolution: - { - integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-arm64@0.27.2': - resolution: - { - integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} + engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/freebsd-x64@0.27.2': - resolution: - { - integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} + engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm64@0.27.2': - resolution: - { - integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-arm@0.27.2': - resolution: - { - integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} + engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-ia32@0.27.2': - resolution: - { - integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} + engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-loong64@0.27.2': - resolution: - { - integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} + engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.27.2': - resolution: - { - integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} + engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-ppc64@0.27.2': - resolution: - { - integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} + engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-riscv64@0.27.2': - resolution: - { - integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} + engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-s390x@0.27.2': - resolution: - { - integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} + engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/linux-x64@0.27.2': - resolution: - { - integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} + engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-arm64@0.27.2': - resolution: - { - integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} + engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/netbsd-x64@0.27.2': - resolution: - { - integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} + engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-arm64@0.27.2': - resolution: - { - integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} + engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openbsd-x64@0.27.2': - resolution: - { - integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} + engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/openharmony-arm64@0.27.2': - resolution: - { - integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} + engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/sunos-x64@0.27.2': - resolution: - { - integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} + engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-arm64@0.27.2': - resolution: - { - integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} + engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-ia32@0.27.2': - resolution: - { - integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} + engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@esbuild/win32-x64@0.27.2': - resolution: - { - integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} + engines: {node: '>=18'} cpu: [x64] os: [win32] '@eslint-community/eslint-utils@4.9.0': - resolution: - { - integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==, - } - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 '@eslint-community/eslint-utils@4.9.1': - resolution: - { - integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==, - } - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 '@eslint-community/regexpp@4.12.2': - resolution: - { - integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==, - } - engines: { node: ^12.0.0 || ^14.0.0 || >=16.0.0 } + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} '@eslint/config-array@0.21.1': - resolution: - { - integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/config-helpers@0.4.2': - resolution: - { - integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/core@0.17.0': - resolution: - { - integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/eslintrc@3.3.3': - resolution: - { - integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/js@9.39.2': - resolution: - { - integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.7': - resolution: - { - integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/plugin-kit@0.4.1': - resolution: - { - integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@graphile-contrib/pg-many-to-many@1.0.2': - resolution: - { - integrity: sha512-ChSaSU7/n99Crdlink62cCGqlEYmjUJKizz2Nx0tdGgqSMkf6KTk00D3ILGybScywMcJGjJE2cc6FXYIHVlxCg==, - } + resolution: {integrity: sha512-ChSaSU7/n99Crdlink62cCGqlEYmjUJKizz2Nx0tdGgqSMkf6KTk00D3ILGybScywMcJGjJE2cc6FXYIHVlxCg==} '@graphile-contrib/pg-simplify-inflector@6.1.0': - resolution: - { - integrity: sha512-3eI2FP4ulu/fxwkJBNXhR6XEzqVz4wJWFr4LfeyUNNArUtLFx0DpP6YdcARCYgwLExFcIQNE8fnul3JKiciYIw==, - } + resolution: {integrity: sha512-3eI2FP4ulu/fxwkJBNXhR6XEzqVz4wJWFr4LfeyUNNArUtLFx0DpP6YdcARCYgwLExFcIQNE8fnul3JKiciYIw==} '@graphile/lru@4.11.0': - resolution: - { - integrity: sha512-Fakuk190EAKxWSa9YQyr/87g8mvAv8HBvk6yPCPuIoA3bYXF7n6kl0XSqKjSd5VfjEqhtnzQ6zJGzDf1Gv/tJg==, - } - engines: { node: '>=8.6' } + resolution: {integrity: sha512-Fakuk190EAKxWSa9YQyr/87g8mvAv8HBvk6yPCPuIoA3bYXF7n6kl0XSqKjSd5VfjEqhtnzQ6zJGzDf1Gv/tJg==} + engines: {node: '>=8.6'} '@graphql-typed-document-node/core@3.2.0': - resolution: - { - integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==, - } + resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 '@humanfs/core@0.19.1': - resolution: - { - integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==, - } - engines: { node: '>=18.18.0' } + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} '@humanfs/node@0.16.7': - resolution: - { - integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==, - } - engines: { node: '>=18.18.0' } + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': - resolution: - { - integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==, - } - engines: { node: '>=12.22' } + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} '@humanwhocodes/retry@0.4.3': - resolution: - { - integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==, - } - engines: { node: '>=18.18' } + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} '@hutson/parse-repository-url@3.0.2': - resolution: - { - integrity: sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==} + engines: {node: '>=6.9.0'} '@inquirer/external-editor@1.0.3': - resolution: - { - integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} + engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: @@ -3655,10 +3425,7 @@ packages: optional: true '@inquirerer/test@1.3.0': - resolution: - { - integrity: sha512-uKn1yJ66MKaPf8ECxoTRma6+lQSLy1YtBOXHDrTGn/j6xtCDdfDYw34h51gM0MLimPTd1vAoxMG+zQGXRSHZLg==, - } + resolution: {integrity: sha512-uKn1yJ66MKaPf8ECxoTRma6+lQSLy1YtBOXHDrTGn/j6xtCDdfDYw34h51gM0MLimPTd1vAoxMG+zQGXRSHZLg==} peerDependencies: jest: '>=29.0.0' peerDependenciesMeta: @@ -3666,65 +3433,46 @@ packages: optional: true '@inquirerer/utils@3.2.0': - resolution: - { - integrity: sha512-poeZdoOH/iDV9dG/J0apH92T5VOGiAgIp8me1yTK9wpEI2qGENyXXBmiYgcE2s+XMHuDr19R9d1UXE9ptaVneA==, - } + resolution: {integrity: sha512-poeZdoOH/iDV9dG/J0apH92T5VOGiAgIp8me1yTK9wpEI2qGENyXXBmiYgcE2s+XMHuDr19R9d1UXE9ptaVneA==} '@isaacs/balanced-match@4.0.1': - resolution: - { - integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==, - } - engines: { node: 20 || >=22 } + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} '@isaacs/brace-expansion@5.0.0': - resolution: - { - integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==, - } - engines: { node: 20 || >=22 } + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.1': + resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==} + engines: {node: 20 || >=22} '@isaacs/cliui@8.0.2': - resolution: - { - integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==, - } - engines: { node: '>=12' } + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@isaacs/cliui@9.0.0': + resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} + engines: {node: '>=18'} '@isaacs/string-locale-compare@1.1.0': - resolution: - { - integrity: sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==, - } + resolution: {integrity: sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==} '@istanbuljs/load-nyc-config@1.1.0': - resolution: - { - integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} '@istanbuljs/schema@0.1.3': - resolution: - { - integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} '@jest/console@30.2.0': - resolution: - { - integrity: sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/core@30.2.0': - resolution: - { - integrity: sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: @@ -3732,67 +3480,40 @@ packages: optional: true '@jest/diff-sequences@30.0.1': - resolution: - { - integrity: sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/environment@30.2.0': - resolution: - { - integrity: sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/expect-utils@30.2.0': - resolution: - { - integrity: sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/expect@30.2.0': - resolution: - { - integrity: sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/fake-timers@30.2.0': - resolution: - { - integrity: sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/get-type@30.1.0': - resolution: - { - integrity: sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/globals@30.2.0': - resolution: - { - integrity: sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/pattern@30.0.1': - resolution: - { - integrity: sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/reporters@30.2.0': - resolution: - { - integrity: sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: @@ -3800,3161 +3521,1922 @@ packages: optional: true '@jest/schemas@29.6.3': - resolution: - { - integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==, - } - engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} '@jest/schemas@30.0.5': - resolution: - { - integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/snapshot-utils@30.2.0': - resolution: - { - integrity: sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/source-map@30.0.1': - resolution: - { - integrity: sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/test-result@30.2.0': - resolution: - { - integrity: sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/test-sequencer@30.2.0': - resolution: - { - integrity: sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/transform@30.2.0': - resolution: - { - integrity: sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/types@26.6.2': - resolution: - { - integrity: sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==, - } - engines: { node: '>= 10.14.2' } + resolution: {integrity: sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==} + engines: {node: '>= 10.14.2'} '@jest/types@30.2.0': - resolution: - { - integrity: sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jridgewell/gen-mapping@0.3.13': - resolution: - { - integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==, - } + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} '@jridgewell/remapping@2.3.5': - resolution: - { - integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==, - } + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} '@jridgewell/resolve-uri@3.1.2': - resolution: - { - integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, - } - engines: { node: '>=6.0.0' } + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} '@jridgewell/sourcemap-codec@1.5.5': - resolution: - { - integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==, - } + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} '@jridgewell/trace-mapping@0.3.31': - resolution: - { - integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==, - } + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} '@jridgewell/trace-mapping@0.3.9': - resolution: - { - integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==, - } + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} '@launchql/mjml@0.1.1': - resolution: - { - integrity: sha512-6+OEmECuu5atRZ43ovsMfFs+T4NWNaKbzNG0uA8HYaBSn3kWR7GH3QnmL3lCIeymLtvgua8aZChYvg6SxrQdnw==, - } + resolution: {integrity: sha512-6+OEmECuu5atRZ43ovsMfFs+T4NWNaKbzNG0uA8HYaBSn3kWR7GH3QnmL3lCIeymLtvgua8aZChYvg6SxrQdnw==} peerDependencies: react: '>=16' react-dom: '>=16' '@launchql/protobufjs@7.2.6': - resolution: - { - integrity: sha512-vwi1nG2/heVFsIMHQU1KxTjUp5c757CTtRAZn/jutApCkFlle1iv8tzM/DHlSZJKDldxaYqnNYTg0pTyp8Bbtg==, - } - engines: { node: '>=12.0.0' } + resolution: {integrity: sha512-vwi1nG2/heVFsIMHQU1KxTjUp5c757CTtRAZn/jutApCkFlle1iv8tzM/DHlSZJKDldxaYqnNYTg0pTyp8Bbtg==} + engines: {node: '>=12.0.0'} '@launchql/styled-email@0.1.0': - resolution: - { - integrity: sha512-ISjzsY+3EOH/qAKHPq3evw9QmmEyA8Vw+0pUf+Zf8l4/rAHJJKrSa/uPiaUf2Abi8yAZKyx2uyaZq4ExNNkD+w==, - } + resolution: {integrity: sha512-ISjzsY+3EOH/qAKHPq3evw9QmmEyA8Vw+0pUf+Zf8l4/rAHJJKrSa/uPiaUf2Abi8yAZKyx2uyaZq4ExNNkD+w==} peerDependencies: react: '>=16' react-dom: '>=16' '@lerna/create@8.2.4': - resolution: - { - integrity: sha512-A8AlzetnS2WIuhijdAzKUyFpR5YbLLfV3luQ4lzBgIBgRfuoBDZeF+RSZPhra+7A6/zTUlrbhKZIOi/MNhqgvQ==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-A8AlzetnS2WIuhijdAzKUyFpR5YbLLfV3luQ4lzBgIBgRfuoBDZeF+RSZPhra+7A6/zTUlrbhKZIOi/MNhqgvQ==} + engines: {node: '>=18.0.0'} '@napi-rs/wasm-runtime@0.2.12': - resolution: - { - integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==, - } + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} '@napi-rs/wasm-runtime@0.2.4': - resolution: - { - integrity: sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==, - } + resolution: {integrity: sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==} '@noble/hashes@1.8.0': - resolution: - { - integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==, - } - engines: { node: ^14.21.3 || >=16 } + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} '@nodelib/fs.scandir@2.1.5': - resolution: - { - integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==, - } - engines: { node: '>= 8' } + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} '@nodelib/fs.stat@2.0.5': - resolution: - { - integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==, - } - engines: { node: '>= 8' } + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} '@nodelib/fs.walk@1.2.8': - resolution: - { - integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==, - } - engines: { node: '>= 8' } + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} '@npmcli/agent@2.2.2': - resolution: - { - integrity: sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==} + engines: {node: ^16.14.0 || >=18.0.0} '@npmcli/arborist@7.5.4': - resolution: - { - integrity: sha512-nWtIc6QwwoUORCRNzKx4ypHqCk3drI+5aeYdMTQQiRCcn4lOOgfQh7WyZobGYTxXPSq1VwV53lkpN/BRlRk08g==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-nWtIc6QwwoUORCRNzKx4ypHqCk3drI+5aeYdMTQQiRCcn4lOOgfQh7WyZobGYTxXPSq1VwV53lkpN/BRlRk08g==} + engines: {node: ^16.14.0 || >=18.0.0} hasBin: true '@npmcli/fs@3.1.1': - resolution: - { - integrity: sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} '@npmcli/git@5.0.8': - resolution: - { - integrity: sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ==} + engines: {node: ^16.14.0 || >=18.0.0} '@npmcli/installed-package-contents@2.1.0': - resolution: - { - integrity: sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} hasBin: true '@npmcli/map-workspaces@3.0.6': - resolution: - { - integrity: sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} '@npmcli/metavuln-calculator@7.1.1': - resolution: - { - integrity: sha512-Nkxf96V0lAx3HCpVda7Vw4P23RILgdi/5K1fmj2tZkWIYLpXAN8k2UVVOsW16TsS5F8Ws2I7Cm+PU1/rsVF47g==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-Nkxf96V0lAx3HCpVda7Vw4P23RILgdi/5K1fmj2tZkWIYLpXAN8k2UVVOsW16TsS5F8Ws2I7Cm+PU1/rsVF47g==} + engines: {node: ^16.14.0 || >=18.0.0} '@npmcli/name-from-folder@2.0.0': - resolution: - { - integrity: sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} '@npmcli/node-gyp@3.0.0': - resolution: - { - integrity: sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} '@npmcli/package-json@5.2.0': - resolution: - { - integrity: sha512-qe/kiqqkW0AGtvBjL8TJKZk/eBBSpnJkUWvHdQ9jM2lKHXRYYJuyNpJPlJw3c8QjC2ow6NZYiLExhUaeJelbxQ==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-qe/kiqqkW0AGtvBjL8TJKZk/eBBSpnJkUWvHdQ9jM2lKHXRYYJuyNpJPlJw3c8QjC2ow6NZYiLExhUaeJelbxQ==} + engines: {node: ^16.14.0 || >=18.0.0} '@npmcli/promise-spawn@7.0.2': - resolution: - { - integrity: sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==} + engines: {node: ^16.14.0 || >=18.0.0} '@npmcli/query@3.1.0': - resolution: - { - integrity: sha512-C/iR0tk7KSKGldibYIB9x8GtO/0Bd0I2mhOaDb8ucQL/bQVTmGoeREaFj64Z5+iCBRf3dQfed0CjJL7I8iTkiQ==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-C/iR0tk7KSKGldibYIB9x8GtO/0Bd0I2mhOaDb8ucQL/bQVTmGoeREaFj64Z5+iCBRf3dQfed0CjJL7I8iTkiQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} '@npmcli/redact@2.0.1': - resolution: - { - integrity: sha512-YgsR5jCQZhVmTJvjduTOIHph0L73pK8xwMVaDY0PatySqVM9AZj93jpoXYSJqfHFxFkN9dmqTw6OiqExsS3LPw==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-YgsR5jCQZhVmTJvjduTOIHph0L73pK8xwMVaDY0PatySqVM9AZj93jpoXYSJqfHFxFkN9dmqTw6OiqExsS3LPw==} + engines: {node: ^16.14.0 || >=18.0.0} '@npmcli/run-script@8.1.0': - resolution: - { - integrity: sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg==} + engines: {node: ^16.14.0 || >=18.0.0} '@nx/devkit@20.8.3': - resolution: - { - integrity: sha512-5lbfJ6ICFOiGeirldQOU5fQ/W/VQ8L3dfWnmHG4UgpWSLoK/YFdRf4lTB4rS0aDXsBL0gyWABz3sZGLPGNYnPA==, - } + resolution: {integrity: sha512-5lbfJ6ICFOiGeirldQOU5fQ/W/VQ8L3dfWnmHG4UgpWSLoK/YFdRf4lTB4rS0aDXsBL0gyWABz3sZGLPGNYnPA==} peerDependencies: nx: '>= 19 <= 21' '@nx/nx-darwin-arm64@20.8.3': - resolution: - { - integrity: sha512-BeYnPAcnaerg6q+qR0bAb0nebwwrsvm4STSVqqVlaqLmmQpU3Bfpx44CEa5d6T9b0V11ZqVE/bkmRhMqhUcrhw==, - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-BeYnPAcnaerg6q+qR0bAb0nebwwrsvm4STSVqqVlaqLmmQpU3Bfpx44CEa5d6T9b0V11ZqVE/bkmRhMqhUcrhw==} + engines: {node: '>= 10'} cpu: [arm64] os: [darwin] '@nx/nx-darwin-x64@20.8.3': - resolution: - { - integrity: sha512-RIFg1VkQ4jhI+ErqEZuIeGBcJGD8t+u9J5CdQBDIASd8QRhtudBkiYLYCJb+qaQly09G7nVfxuyItlS2uRW3qA==, - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-RIFg1VkQ4jhI+ErqEZuIeGBcJGD8t+u9J5CdQBDIASd8QRhtudBkiYLYCJb+qaQly09G7nVfxuyItlS2uRW3qA==} + engines: {node: '>= 10'} cpu: [x64] os: [darwin] '@nx/nx-freebsd-x64@20.8.3': - resolution: - { - integrity: sha512-boQTgMUdnqpZhHMrV/xgnp/dTg5dfxw8I4d16NBwmW4j+Sez7zi/dydgsJpfZsj8TicOHvPu6KK4W5wzp82NPw==, - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-boQTgMUdnqpZhHMrV/xgnp/dTg5dfxw8I4d16NBwmW4j+Sez7zi/dydgsJpfZsj8TicOHvPu6KK4W5wzp82NPw==} + engines: {node: '>= 10'} cpu: [x64] os: [freebsd] '@nx/nx-linux-arm-gnueabihf@20.8.3': - resolution: - { - integrity: sha512-wpiNyY1igx1rLN3EsTLum2lDtblFijdBZB9/9u/6UDub4z9CaQ4yaC4h9n5v7yFYILwfL44YTsQKzrE+iv0y1Q==, - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-wpiNyY1igx1rLN3EsTLum2lDtblFijdBZB9/9u/6UDub4z9CaQ4yaC4h9n5v7yFYILwfL44YTsQKzrE+iv0y1Q==} + engines: {node: '>= 10'} cpu: [arm] os: [linux] '@nx/nx-linux-arm64-gnu@20.8.3': - resolution: - { - integrity: sha512-nbi/eZtJfWxuDwdUCiP+VJolFubtrz6XxVtB26eMAkODnREOKELHZtMOrlm8JBZCdtWCvTqibq9Az74XsqSfdA==, - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-nbi/eZtJfWxuDwdUCiP+VJolFubtrz6XxVtB26eMAkODnREOKELHZtMOrlm8JBZCdtWCvTqibq9Az74XsqSfdA==} + engines: {node: '>= 10'} cpu: [arm64] os: [linux] '@nx/nx-linux-arm64-musl@20.8.3': - resolution: - { - integrity: sha512-LTTGzI8YVPlF1v0YlVf+exM+1q7rpsiUbjTTHJcfHFRU5t4BsiZD54K19Y1UBg1XFx5cwhEaIomSmJ88RwPPVQ==, - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-LTTGzI8YVPlF1v0YlVf+exM+1q7rpsiUbjTTHJcfHFRU5t4BsiZD54K19Y1UBg1XFx5cwhEaIomSmJ88RwPPVQ==} + engines: {node: '>= 10'} cpu: [arm64] os: [linux] '@nx/nx-linux-x64-gnu@20.8.3': - resolution: - { - integrity: sha512-SlA4GtXvQbSzSIWLgiIiLBOjdINPOUR/im+TUbaEMZ8wiGrOY8cnk0PVt95TIQJVBeXBCeb5HnoY0lHJpMOODg==, - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-SlA4GtXvQbSzSIWLgiIiLBOjdINPOUR/im+TUbaEMZ8wiGrOY8cnk0PVt95TIQJVBeXBCeb5HnoY0lHJpMOODg==} + engines: {node: '>= 10'} cpu: [x64] os: [linux] '@nx/nx-linux-x64-musl@20.8.3': - resolution: - { - integrity: sha512-MNzkEwPktp5SQH9dJDH2wP9hgG9LsBDhKJXJfKw6sUI/6qz5+/aAjFziKy+zBnhU4AO1yXt5qEWzR8lDcIriVQ==, - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-MNzkEwPktp5SQH9dJDH2wP9hgG9LsBDhKJXJfKw6sUI/6qz5+/aAjFziKy+zBnhU4AO1yXt5qEWzR8lDcIriVQ==} + engines: {node: '>= 10'} cpu: [x64] os: [linux] '@nx/nx-win32-arm64-msvc@20.8.3': - resolution: - { - integrity: sha512-qUV7CyXKwRCM/lkvyS6Xa1MqgAuK5da6w27RAehh7LATBUKn1I4/M7DGn6L7ERCxpZuh1TrDz9pUzEy0R+Ekkg==, - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-qUV7CyXKwRCM/lkvyS6Xa1MqgAuK5da6w27RAehh7LATBUKn1I4/M7DGn6L7ERCxpZuh1TrDz9pUzEy0R+Ekkg==} + engines: {node: '>= 10'} cpu: [arm64] os: [win32] '@nx/nx-win32-x64-msvc@20.8.3': - resolution: - { - integrity: sha512-gX1G8u6W6EPX6PO/wv07+B++UHyCHBXyVWXITA3Kv6HoSajOxIa2Kk1rv1iDQGmX1WWxBaj3bUyYJAFBDITe4w==, - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-gX1G8u6W6EPX6PO/wv07+B++UHyCHBXyVWXITA3Kv6HoSajOxIa2Kk1rv1iDQGmX1WWxBaj3bUyYJAFBDITe4w==} + engines: {node: '>= 10'} cpu: [x64] os: [win32] '@octokit/auth-token@4.0.0': - resolution: - { - integrity: sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==, - } - engines: { node: '>= 18' } + resolution: {integrity: sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==} + engines: {node: '>= 18'} '@octokit/core@5.2.2': - resolution: - { - integrity: sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==, - } - engines: { node: '>= 18' } + resolution: {integrity: sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==} + engines: {node: '>= 18'} '@octokit/endpoint@9.0.6': - resolution: - { - integrity: sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==, - } - engines: { node: '>= 18' } + resolution: {integrity: sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==} + engines: {node: '>= 18'} '@octokit/graphql@7.1.1': - resolution: - { - integrity: sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==, - } - engines: { node: '>= 18' } + resolution: {integrity: sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==} + engines: {node: '>= 18'} '@octokit/openapi-types@24.2.0': - resolution: - { - integrity: sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==, - } + resolution: {integrity: sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==} '@octokit/plugin-enterprise-rest@6.0.1': - resolution: - { - integrity: sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==, - } + resolution: {integrity: sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==} '@octokit/plugin-paginate-rest@11.4.4-cjs.2': - resolution: - { - integrity: sha512-2dK6z8fhs8lla5PaOTgqfCGBxgAv/le+EhPs27KklPhm1bKObpu6lXzwfUEQ16ajXzqNrKMujsFyo9K2eaoISw==, - } - engines: { node: '>= 18' } + resolution: {integrity: sha512-2dK6z8fhs8lla5PaOTgqfCGBxgAv/le+EhPs27KklPhm1bKObpu6lXzwfUEQ16ajXzqNrKMujsFyo9K2eaoISw==} + engines: {node: '>= 18'} peerDependencies: '@octokit/core': '5' '@octokit/plugin-request-log@4.0.1': - resolution: - { - integrity: sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA==, - } - engines: { node: '>= 18' } + resolution: {integrity: sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA==} + engines: {node: '>= 18'} peerDependencies: '@octokit/core': '5' '@octokit/plugin-rest-endpoint-methods@13.3.2-cjs.1': - resolution: - { - integrity: sha512-VUjIjOOvF2oELQmiFpWA1aOPdawpyaCUqcEBc/UOUnj3Xp6DJGrJ1+bjUIIDzdHjnFNO6q57ODMfdEZnoBkCwQ==, - } - engines: { node: '>= 18' } + resolution: {integrity: sha512-VUjIjOOvF2oELQmiFpWA1aOPdawpyaCUqcEBc/UOUnj3Xp6DJGrJ1+bjUIIDzdHjnFNO6q57ODMfdEZnoBkCwQ==} + engines: {node: '>= 18'} peerDependencies: '@octokit/core': ^5 '@octokit/request-error@5.1.1': - resolution: - { - integrity: sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==, - } - engines: { node: '>= 18' } + resolution: {integrity: sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==} + engines: {node: '>= 18'} '@octokit/request@8.4.1': - resolution: - { - integrity: sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==, - } - engines: { node: '>= 18' } + resolution: {integrity: sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==} + engines: {node: '>= 18'} '@octokit/rest@20.1.2': - resolution: - { - integrity: sha512-GmYiltypkHHtihFwPRxlaorG5R9VAHuk/vbszVoRTGXnAsY60wYLkh/E2XiFmdZmqrisw+9FaazS1i5SbdWYgA==, - } - engines: { node: '>= 18' } + resolution: {integrity: sha512-GmYiltypkHHtihFwPRxlaorG5R9VAHuk/vbszVoRTGXnAsY60wYLkh/E2XiFmdZmqrisw+9FaazS1i5SbdWYgA==} + engines: {node: '>= 18'} '@octokit/types@13.10.0': - resolution: - { - integrity: sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==, - } + resolution: {integrity: sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==} '@one-ini/wasm@0.1.1': - resolution: - { - integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==, - } + resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} '@oxfmt/darwin-arm64@0.26.0': - resolution: - { - integrity: sha512-AAGc+8CffkiWeVgtWf4dPfQwHEE5c/j/8NWH7VGVxxJRCZFdmWcqCXprvL2H6qZFewvDLrFbuSPRCqYCpYGaTQ==, - } + resolution: {integrity: sha512-AAGc+8CffkiWeVgtWf4dPfQwHEE5c/j/8NWH7VGVxxJRCZFdmWcqCXprvL2H6qZFewvDLrFbuSPRCqYCpYGaTQ==} cpu: [arm64] os: [darwin] '@oxfmt/darwin-x64@0.26.0': - resolution: - { - integrity: sha512-xFx5ijCTjw577wJvFlZEMmKDnp3HSCcbYdCsLRmC5i3TZZiDe9DEYh3P46uqhzj8BkEw1Vm1ZCWdl48aEYAzvQ==, - } + resolution: {integrity: sha512-xFx5ijCTjw577wJvFlZEMmKDnp3HSCcbYdCsLRmC5i3TZZiDe9DEYh3P46uqhzj8BkEw1Vm1ZCWdl48aEYAzvQ==} cpu: [x64] os: [darwin] '@oxfmt/linux-arm64-gnu@0.26.0': - resolution: - { - integrity: sha512-GubkQeQT5d3B/Jx/IiR7NMkSmXrCZcVI0BPh1i7mpFi8HgD1hQ/LbhiBKAMsMqs5bbugdQOgBEl8bOhe8JhW1g==, - } + resolution: {integrity: sha512-GubkQeQT5d3B/Jx/IiR7NMkSmXrCZcVI0BPh1i7mpFi8HgD1hQ/LbhiBKAMsMqs5bbugdQOgBEl8bOhe8JhW1g==} cpu: [arm64] os: [linux] '@oxfmt/linux-arm64-musl@0.26.0': - resolution: - { - integrity: sha512-OEypUwK69bFPj+aa3/LYCnlIUPgoOLu//WNcriwpnWNmt47808Ht7RJSg+MNK8a7pSZHpXJ5/E6CRK/OTwFdaQ==, - } + resolution: {integrity: sha512-OEypUwK69bFPj+aa3/LYCnlIUPgoOLu//WNcriwpnWNmt47808Ht7RJSg+MNK8a7pSZHpXJ5/E6CRK/OTwFdaQ==} cpu: [arm64] os: [linux] '@oxfmt/linux-x64-gnu@0.26.0': - resolution: - { - integrity: sha512-xO6iEW2bC6ZHyOTPmPWrg/nM6xgzyRPaS84rATy6F8d79wz69LdRdJ3l/PXlkqhi7XoxhvX4ExysA0Nf10ZZEQ==, - } + resolution: {integrity: sha512-xO6iEW2bC6ZHyOTPmPWrg/nM6xgzyRPaS84rATy6F8d79wz69LdRdJ3l/PXlkqhi7XoxhvX4ExysA0Nf10ZZEQ==} cpu: [x64] os: [linux] '@oxfmt/linux-x64-musl@0.26.0': - resolution: - { - integrity: sha512-Z3KuZFC+MIuAyFCXBHY71kCsdRq1ulbsbzTe71v+hrEv7zVBn6yzql+/AZcgfIaKzWO9OXNuz5WWLWDmVALwow==, - } + resolution: {integrity: sha512-Z3KuZFC+MIuAyFCXBHY71kCsdRq1ulbsbzTe71v+hrEv7zVBn6yzql+/AZcgfIaKzWO9OXNuz5WWLWDmVALwow==} cpu: [x64] os: [linux] '@oxfmt/win32-arm64@0.26.0': - resolution: - { - integrity: sha512-3zRbqwVWK1mDhRhTknlQFpRFL9GhEB5GfU6U7wawnuEwpvi39q91kJ+SRJvJnhyPCARkjZBd1V8XnweN5IFd1g==, - } + resolution: {integrity: sha512-3zRbqwVWK1mDhRhTknlQFpRFL9GhEB5GfU6U7wawnuEwpvi39q91kJ+SRJvJnhyPCARkjZBd1V8XnweN5IFd1g==} cpu: [arm64] os: [win32] '@oxfmt/win32-x64@0.26.0': - resolution: - { - integrity: sha512-m8TfIljU22i9UEIkD+slGPifTFeaCwIUfxszN3E6ABWP1KQbtwSw9Ak0TdoikibvukF/dtbeyG3WW63jv9DnEg==, - } + resolution: {integrity: sha512-m8TfIljU22i9UEIkD+slGPifTFeaCwIUfxszN3E6ABWP1KQbtwSw9Ak0TdoikibvukF/dtbeyG3WW63jv9DnEg==} cpu: [x64] os: [win32] '@paralleldrive/cuid2@2.3.1': - resolution: - { - integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==, - } + resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==} '@pgpm/database-jobs@0.16.0': - resolution: - { - integrity: sha512-s8I7958PlhfYXZKhYoU76R03yk6dlevjGk/Uy9uktveJkZ8C3JVsIhP6Lv4lo0SFEZCjFmXRCYpOY5xINIcX4w==, - } + resolution: {integrity: sha512-s8I7958PlhfYXZKhYoU76R03yk6dlevjGk/Uy9uktveJkZ8C3JVsIhP6Lv4lo0SFEZCjFmXRCYpOY5xINIcX4w==} '@pgpm/inflection@0.16.0': - resolution: - { - integrity: sha512-otjWGx+KkB113Wc5I9nsvoqPhBK6zD1ON2OcXw9PQRgqU43Y9f0yZjb559dDzZwDn5XUeiZMf6il5SIvJE5NPg==, - } + resolution: {integrity: sha512-otjWGx+KkB113Wc5I9nsvoqPhBK6zD1ON2OcXw9PQRgqU43Y9f0yZjb559dDzZwDn5XUeiZMf6il5SIvJE5NPg==} '@pgpm/metaschema-modules@0.16.4': - resolution: - { - integrity: sha512-sB3+5yljFEqUXTTHUOHBBxK52CwagHiUBumWjikHVN9C5w6NHUQ+xFde+3RJMCkoqnmcZn6HTGvWCF25QgciiA==, - } + resolution: {integrity: sha512-sB3+5yljFEqUXTTHUOHBBxK52CwagHiUBumWjikHVN9C5w6NHUQ+xFde+3RJMCkoqnmcZn6HTGvWCF25QgciiA==} '@pgpm/metaschema-schema@0.16.3': - resolution: - { - integrity: sha512-sDIWJY+uNaqMMGjL8NWo8ezzXH1OT0qdaqsX+YDrBL6v1u0PphWprdjd7HySzdqIGpPSax8sIy5u4P2M96wR9Q==, - } + resolution: {integrity: sha512-sDIWJY+uNaqMMGjL8NWo8ezzXH1OT0qdaqsX+YDrBL6v1u0PphWprdjd7HySzdqIGpPSax8sIy5u4P2M96wR9Q==} '@pgpm/services@0.16.3': - resolution: - { - integrity: sha512-TfYALB8RKPyR2WZIFH2Pirb5qfx1q2EKbr7gzG/CcZcQMgTGYyDHBtvSqIO4nDfJ6GgYcASoip9T0lzQmwGtlA==, - } + resolution: {integrity: sha512-TfYALB8RKPyR2WZIFH2Pirb5qfx1q2EKbr7gzG/CcZcQMgTGYyDHBtvSqIO4nDfJ6GgYcASoip9T0lzQmwGtlA==} '@pgpm/types@0.16.0': - resolution: - { - integrity: sha512-CioHCxZGQUnpLANw4aMOOq7Z6zi2SXCxJIRZ8CSBPJfJkWU1OgxX+EpSjnm4Td4bznJhOViXniLltibaaGkMPA==, - } + resolution: {integrity: sha512-CioHCxZGQUnpLANw4aMOOq7Z6zi2SXCxJIRZ8CSBPJfJkWU1OgxX+EpSjnm4Td4bznJhOViXniLltibaaGkMPA==} '@pgpm/verify@0.16.0': - resolution: - { - integrity: sha512-uG0zTXAWGLV8wTUiLdBn+2b4AO+gtiw7sZf+TFFU8h/mVGMBTHUb9Gbsl/GL/5/0zZKOxak7cRJ5deec79KB/A==, - } + resolution: {integrity: sha512-uG0zTXAWGLV8wTUiLdBn+2b4AO+gtiw7sZf+TFFU8h/mVGMBTHUb9Gbsl/GL/5/0zZKOxak7cRJ5deec79KB/A==} '@pgsql/types@17.6.2': - resolution: - { - integrity: sha512-1UtbELdbqNdyOShhrVfSz3a1gDi0s9XXiQemx+6QqtsrXe62a6zOGU+vjb2GRfG5jeEokI1zBBcfD42enRv0Rw==, - } + resolution: {integrity: sha512-1UtbELdbqNdyOShhrVfSz3a1gDi0s9XXiQemx+6QqtsrXe62a6zOGU+vjb2GRfG5jeEokI1zBBcfD42enRv0Rw==} '@pgsql/utils@17.8.11': - resolution: - { - integrity: sha512-gcaS9ATilQyGSIq8596tq+6rcb7TX54sdjOvOzGa9lu9NjqkptEKLbBae5UTjfkFGfH50duDFD1EpFogMnZToA==, - } + resolution: {integrity: sha512-gcaS9ATilQyGSIq8596tq+6rcb7TX54sdjOvOzGa9lu9NjqkptEKLbBae5UTjfkFGfH50duDFD1EpFogMnZToA==} '@pkgjs/parseargs@0.11.0': - resolution: - { - integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} '@pkgr/core@0.2.9': - resolution: - { - integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==, - } - engines: { node: ^12.20.0 || ^14.18.0 || >=16.0.0 } + resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} '@playwright/test@1.57.0': - resolution: - { - integrity: sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==} + engines: {node: '>=18'} hasBin: true '@protobufjs/aspromise@1.1.2': - resolution: - { - integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==, - } + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} '@protobufjs/base64@1.1.2': - resolution: - { - integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==, - } + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} '@protobufjs/codegen@2.0.4': - resolution: - { - integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==, - } + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} '@protobufjs/eventemitter@1.1.0': - resolution: - { - integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==, - } + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} '@protobufjs/fetch@1.1.0': - resolution: - { - integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==, - } + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} '@protobufjs/float@1.0.2': - resolution: - { - integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==, - } + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} '@protobufjs/inquire@1.1.0': - resolution: - { - integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==, - } + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} '@protobufjs/path@1.1.2': - resolution: - { - integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==, - } + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} '@protobufjs/pool@1.1.0': - resolution: - { - integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==, - } + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} '@protobufjs/utf8@1.1.0': - resolution: - { - integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==, - } + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + + '@rolldown/pluginutils@1.0.0-beta.27': + resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + + '@rollup/rollup-android-arm-eabi@4.57.1': + resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.57.1': + resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.57.1': + resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.57.1': + resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.57.1': + resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.57.1': + resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.57.1': + resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.57.1': + resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.57.1': + resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.57.1': + resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.57.1': + resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.57.1': + resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.57.1': + resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.57.1': + resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.57.1': + resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.57.1': + resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.57.1': + resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.57.1': + resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.57.1': + resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.57.1': + resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.57.1': + resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.57.1': + resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.57.1': + resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.57.1': + resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.57.1': + resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==} + cpu: [x64] + os: [win32] '@sigstore/bundle@2.3.2': - resolution: - { - integrity: sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA==} + engines: {node: ^16.14.0 || >=18.0.0} '@sigstore/core@1.1.0': - resolution: - { - integrity: sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==} + engines: {node: ^16.14.0 || >=18.0.0} '@sigstore/protobuf-specs@0.3.3': - resolution: - { - integrity: sha512-RpacQhBlwpBWd7KEJsRKcBQalbV28fvkxwTOJIqhIuDysMMaJW47V4OqW30iJB9uRpqOSxxEAQFdr8tTattReQ==, - } - engines: { node: ^18.17.0 || >=20.5.0 } + resolution: {integrity: sha512-RpacQhBlwpBWd7KEJsRKcBQalbV28fvkxwTOJIqhIuDysMMaJW47V4OqW30iJB9uRpqOSxxEAQFdr8tTattReQ==} + engines: {node: ^18.17.0 || >=20.5.0} '@sigstore/sign@2.3.2': - resolution: - { - integrity: sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA==} + engines: {node: ^16.14.0 || >=18.0.0} '@sigstore/tuf@2.3.4': - resolution: - { - integrity: sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw==} + engines: {node: ^16.14.0 || >=18.0.0} '@sigstore/verify@1.2.1': - resolution: - { - integrity: sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g==} + engines: {node: ^16.14.0 || >=18.0.0} '@sinclair/typebox@0.27.8': - resolution: - { - integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==, - } + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} '@sinclair/typebox@0.34.47': - resolution: - { - integrity: sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw==, - } + resolution: {integrity: sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw==} '@sinonjs/commons@3.0.1': - resolution: - { - integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==, - } + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} '@sinonjs/fake-timers@13.0.5': - resolution: - { - integrity: sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==, - } + resolution: {integrity: sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==} '@smithy/abort-controller@4.2.7': - resolution: - { - integrity: sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw==} + engines: {node: '>=18.0.0'} '@smithy/abort-controller@4.2.8': - resolution: - { - integrity: sha512-peuVfkYHAmS5ybKxWcfraK7WBBP0J+rkfUcbHJJKQ4ir3UAUNQI+Y4Vt/PqSzGqgloJ5O1dk7+WzNL8wcCSXbw==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-peuVfkYHAmS5ybKxWcfraK7WBBP0J+rkfUcbHJJKQ4ir3UAUNQI+Y4Vt/PqSzGqgloJ5O1dk7+WzNL8wcCSXbw==} + engines: {node: '>=18.0.0'} '@smithy/chunked-blob-reader-native@4.2.1': - resolution: - { - integrity: sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ==} + engines: {node: '>=18.0.0'} '@smithy/chunked-blob-reader@5.2.0': - resolution: - { - integrity: sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA==} + engines: {node: '>=18.0.0'} '@smithy/config-resolver@4.4.6': - resolution: - { - integrity: sha512-qJpzYC64kaj3S0fueiu3kXm8xPrR3PcXDPEgnaNMRn0EjNSZFoFjvbUp0YUDsRhN1CB90EnHJtbxWKevnH99UQ==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-qJpzYC64kaj3S0fueiu3kXm8xPrR3PcXDPEgnaNMRn0EjNSZFoFjvbUp0YUDsRhN1CB90EnHJtbxWKevnH99UQ==} + engines: {node: '>=18.0.0'} '@smithy/core@3.20.0': - resolution: - { - integrity: sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ==} + engines: {node: '>=18.0.0'} '@smithy/core@3.20.5': - resolution: - { - integrity: sha512-0Tz77Td8ynHaowXfOdrD0F1IH4tgWGUhwmLwmpFyTbr+U9WHXNNp9u/k2VjBXGnSe7BwjBERRpXsokGTXzNjhA==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-0Tz77Td8ynHaowXfOdrD0F1IH4tgWGUhwmLwmpFyTbr+U9WHXNNp9u/k2VjBXGnSe7BwjBERRpXsokGTXzNjhA==} + engines: {node: '>=18.0.0'} '@smithy/core@3.20.7': - resolution: - { - integrity: sha512-aO7jmh3CtrmPsIJxUwYIzI5WVlMK8BMCPQ4D4nTzqTqBhbzvxHNzBMGcEg13yg/z9R2Qsz49NUFl0F0lVbTVFw==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-aO7jmh3CtrmPsIJxUwYIzI5WVlMK8BMCPQ4D4nTzqTqBhbzvxHNzBMGcEg13yg/z9R2Qsz49NUFl0F0lVbTVFw==} + engines: {node: '>=18.0.0'} '@smithy/credential-provider-imds@4.2.8': - resolution: - { - integrity: sha512-FNT0xHS1c/CPN8upqbMFP83+ul5YgdisfCfkZ86Jh2NSmnqw/AJ6x5pEogVCTVvSm7j9MopRU89bmDelxuDMYw==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-FNT0xHS1c/CPN8upqbMFP83+ul5YgdisfCfkZ86Jh2NSmnqw/AJ6x5pEogVCTVvSm7j9MopRU89bmDelxuDMYw==} + engines: {node: '>=18.0.0'} '@smithy/eventstream-codec@4.2.8': - resolution: - { - integrity: sha512-jS/O5Q14UsufqoGhov7dHLOPCzkYJl9QDzusI2Psh4wyYx/izhzvX9P4D69aTxcdfVhEPhjK+wYyn/PzLjKbbw==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-jS/O5Q14UsufqoGhov7dHLOPCzkYJl9QDzusI2Psh4wyYx/izhzvX9P4D69aTxcdfVhEPhjK+wYyn/PzLjKbbw==} + engines: {node: '>=18.0.0'} '@smithy/eventstream-serde-browser@4.2.8': - resolution: - { - integrity: sha512-MTfQT/CRQz5g24ayXdjg53V0mhucZth4PESoA5IhvaWVDTOQLfo8qI9vzqHcPsdd2v6sqfTYqF5L/l+pea5Uyw==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-MTfQT/CRQz5g24ayXdjg53V0mhucZth4PESoA5IhvaWVDTOQLfo8qI9vzqHcPsdd2v6sqfTYqF5L/l+pea5Uyw==} + engines: {node: '>=18.0.0'} '@smithy/eventstream-serde-config-resolver@4.3.8': - resolution: - { - integrity: sha512-ah12+luBiDGzBruhu3efNy1IlbwSEdNiw8fOZksoKoWW1ZHvO/04MQsdnws/9Aj+5b0YXSSN2JXKy/ClIsW8MQ==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-ah12+luBiDGzBruhu3efNy1IlbwSEdNiw8fOZksoKoWW1ZHvO/04MQsdnws/9Aj+5b0YXSSN2JXKy/ClIsW8MQ==} + engines: {node: '>=18.0.0'} '@smithy/eventstream-serde-node@4.2.8': - resolution: - { - integrity: sha512-cYpCpp29z6EJHa5T9WL0KAlq3SOKUQkcgSoeRfRVwjGgSFl7Uh32eYGt7IDYCX20skiEdRffyDpvF2efEZPC0A==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-cYpCpp29z6EJHa5T9WL0KAlq3SOKUQkcgSoeRfRVwjGgSFl7Uh32eYGt7IDYCX20skiEdRffyDpvF2efEZPC0A==} + engines: {node: '>=18.0.0'} '@smithy/eventstream-serde-universal@4.2.8': - resolution: - { - integrity: sha512-iJ6YNJd0bntJYnX6s52NC4WFYcZeKrPUr1Kmmr5AwZcwCSzVpS7oavAmxMR7pMq7V+D1G4s9F5NJK0xwOsKAlQ==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-iJ6YNJd0bntJYnX6s52NC4WFYcZeKrPUr1Kmmr5AwZcwCSzVpS7oavAmxMR7pMq7V+D1G4s9F5NJK0xwOsKAlQ==} + engines: {node: '>=18.0.0'} '@smithy/fetch-http-handler@5.3.8': - resolution: - { - integrity: sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg==} + engines: {node: '>=18.0.0'} '@smithy/fetch-http-handler@5.3.9': - resolution: - { - integrity: sha512-I4UhmcTYXBrct03rwzQX1Y/iqQlzVQaPxWjCjula++5EmWq9YGBrx6bbGqluGc1f0XEfhSkiY4jhLgbsJUMKRA==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-I4UhmcTYXBrct03rwzQX1Y/iqQlzVQaPxWjCjula++5EmWq9YGBrx6bbGqluGc1f0XEfhSkiY4jhLgbsJUMKRA==} + engines: {node: '>=18.0.0'} '@smithy/hash-blob-browser@4.2.9': - resolution: - { - integrity: sha512-m80d/iicI7DlBDxyQP6Th7BW/ejDGiF0bgI754+tiwK0lgMkcaIBgvwwVc7OFbY4eUzpGtnig52MhPAEJ7iNYg==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-m80d/iicI7DlBDxyQP6Th7BW/ejDGiF0bgI754+tiwK0lgMkcaIBgvwwVc7OFbY4eUzpGtnig52MhPAEJ7iNYg==} + engines: {node: '>=18.0.0'} '@smithy/hash-node@4.2.8': - resolution: - { - integrity: sha512-7ZIlPbmaDGxVoxErDZnuFG18WekhbA/g2/i97wGj+wUBeS6pcUeAym8u4BXh/75RXWhgIJhyC11hBzig6MljwA==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-7ZIlPbmaDGxVoxErDZnuFG18WekhbA/g2/i97wGj+wUBeS6pcUeAym8u4BXh/75RXWhgIJhyC11hBzig6MljwA==} + engines: {node: '>=18.0.0'} '@smithy/hash-stream-node@4.2.8': - resolution: - { - integrity: sha512-v0FLTXgHrTeheYZFGhR+ehX5qUm4IQsjAiL9qehad2cyjMWcN2QG6/4mSwbSgEQzI7jwfoXj7z4fxZUx/Mhj2w==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-v0FLTXgHrTeheYZFGhR+ehX5qUm4IQsjAiL9qehad2cyjMWcN2QG6/4mSwbSgEQzI7jwfoXj7z4fxZUx/Mhj2w==} + engines: {node: '>=18.0.0'} '@smithy/invalid-dependency@4.2.8': - resolution: - { - integrity: sha512-N9iozRybwAQ2dn9Fot9kI6/w9vos2oTXLhtK7ovGqwZjlOcxu6XhPlpLpC+INsxktqHinn5gS2DXDjDF2kG5sQ==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-N9iozRybwAQ2dn9Fot9kI6/w9vos2oTXLhtK7ovGqwZjlOcxu6XhPlpLpC+INsxktqHinn5gS2DXDjDF2kG5sQ==} + engines: {node: '>=18.0.0'} '@smithy/is-array-buffer@2.2.0': - resolution: - { - integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==, - } - engines: { node: '>=14.0.0' } + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} '@smithy/is-array-buffer@4.2.0': - resolution: - { - integrity: sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ==} + engines: {node: '>=18.0.0'} '@smithy/md5-js@4.2.8': - resolution: - { - integrity: sha512-oGMaLj4tVZzLi3itBa9TCswgMBr7k9b+qKYowQ6x1rTyTuO1IU2YHdHUa+891OsOH+wCsH7aTPRsTJO3RMQmjQ==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-oGMaLj4tVZzLi3itBa9TCswgMBr7k9b+qKYowQ6x1rTyTuO1IU2YHdHUa+891OsOH+wCsH7aTPRsTJO3RMQmjQ==} + engines: {node: '>=18.0.0'} '@smithy/middleware-content-length@4.2.8': - resolution: - { - integrity: sha512-RO0jeoaYAB1qBRhfVyq0pMgBoUK34YEJxVxyjOWYZiOKOq2yMZ4MnVXMZCUDenpozHue207+9P5ilTV1zeda0A==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-RO0jeoaYAB1qBRhfVyq0pMgBoUK34YEJxVxyjOWYZiOKOq2yMZ4MnVXMZCUDenpozHue207+9P5ilTV1zeda0A==} + engines: {node: '>=18.0.0'} '@smithy/middleware-endpoint@4.4.1': - resolution: - { - integrity: sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg==} + engines: {node: '>=18.0.0'} '@smithy/middleware-endpoint@4.4.6': - resolution: - { - integrity: sha512-dpq3bHqbEOBqGBjRVHVFP3eUSPpX0BYtg1D5d5Irgk6orGGAuZfY22rC4sErhg+ZfY/Y0kPqm1XpAmDZg7DeuA==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-dpq3bHqbEOBqGBjRVHVFP3eUSPpX0BYtg1D5d5Irgk6orGGAuZfY22rC4sErhg+ZfY/Y0kPqm1XpAmDZg7DeuA==} + engines: {node: '>=18.0.0'} '@smithy/middleware-endpoint@4.4.8': - resolution: - { - integrity: sha512-TV44qwB/T0OMMzjIuI+JeS0ort3bvlPJ8XIH0MSlGADraXpZqmyND27ueuAL3E14optleADWqtd7dUgc2w+qhQ==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-TV44qwB/T0OMMzjIuI+JeS0ort3bvlPJ8XIH0MSlGADraXpZqmyND27ueuAL3E14optleADWqtd7dUgc2w+qhQ==} + engines: {node: '>=18.0.0'} '@smithy/middleware-retry@4.4.22': - resolution: - { - integrity: sha512-vwWDMaObSMjw6WCC/3Ae9G7uul5Sk95jr07CDk1gkIMpaDic0phPS1MpVAZ6+YkF7PAzRlpsDjxPwRlh/S11FQ==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-vwWDMaObSMjw6WCC/3Ae9G7uul5Sk95jr07CDk1gkIMpaDic0phPS1MpVAZ6+YkF7PAzRlpsDjxPwRlh/S11FQ==} + engines: {node: '>=18.0.0'} '@smithy/middleware-retry@4.4.24': - resolution: - { - integrity: sha512-yiUY1UvnbUFfP5izoKLtfxDSTRv724YRRwyiC/5HYY6vdsVDcDOXKSXmkJl/Hovcxt5r+8tZEUAdrOaCJwrl9Q==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-yiUY1UvnbUFfP5izoKLtfxDSTRv724YRRwyiC/5HYY6vdsVDcDOXKSXmkJl/Hovcxt5r+8tZEUAdrOaCJwrl9Q==} + engines: {node: '>=18.0.0'} '@smithy/middleware-serde@4.2.8': - resolution: - { - integrity: sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w==} + engines: {node: '>=18.0.0'} '@smithy/middleware-serde@4.2.9': - resolution: - { - integrity: sha512-eMNiej0u/snzDvlqRGSN3Vl0ESn3838+nKyVfF2FKNXFbi4SERYT6PR392D39iczngbqqGG0Jl1DlCnp7tBbXQ==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-eMNiej0u/snzDvlqRGSN3Vl0ESn3838+nKyVfF2FKNXFbi4SERYT6PR392D39iczngbqqGG0Jl1DlCnp7tBbXQ==} + engines: {node: '>=18.0.0'} '@smithy/middleware-stack@4.2.7': - resolution: - { - integrity: sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw==} + engines: {node: '>=18.0.0'} '@smithy/middleware-stack@4.2.8': - resolution: - { - integrity: sha512-w6LCfOviTYQjBctOKSwy6A8FIkQy7ICvglrZFl6Bw4FmcQ1Z420fUtIhxaUZZshRe0VCq4kvDiPiXrPZAe8oRA==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-w6LCfOviTYQjBctOKSwy6A8FIkQy7ICvglrZFl6Bw4FmcQ1Z420fUtIhxaUZZshRe0VCq4kvDiPiXrPZAe8oRA==} + engines: {node: '>=18.0.0'} '@smithy/node-config-provider@4.3.7': - resolution: - { - integrity: sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw==} + engines: {node: '>=18.0.0'} '@smithy/node-config-provider@4.3.8': - resolution: - { - integrity: sha512-aFP1ai4lrbVlWjfpAfRSL8KFcnJQYfTl5QxLJXY32vghJrDuFyPZ6LtUL+JEGYiFRG1PfPLHLoxj107ulncLIg==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-aFP1ai4lrbVlWjfpAfRSL8KFcnJQYfTl5QxLJXY32vghJrDuFyPZ6LtUL+JEGYiFRG1PfPLHLoxj107ulncLIg==} + engines: {node: '>=18.0.0'} '@smithy/node-http-handler@4.4.7': - resolution: - { - integrity: sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ==} + engines: {node: '>=18.0.0'} '@smithy/node-http-handler@4.4.8': - resolution: - { - integrity: sha512-q9u+MSbJVIJ1QmJ4+1u+cERXkrhuILCBDsJUBAW1MPE6sFonbCNaegFuwW9ll8kh5UdyY3jOkoOGlc7BesoLpg==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-q9u+MSbJVIJ1QmJ4+1u+cERXkrhuILCBDsJUBAW1MPE6sFonbCNaegFuwW9ll8kh5UdyY3jOkoOGlc7BesoLpg==} + engines: {node: '>=18.0.0'} '@smithy/property-provider@4.2.7': - resolution: - { - integrity: sha512-jmNYKe9MGGPoSl/D7JDDs1C8b3dC8f/w78LbaVfoTtWy4xAd5dfjaFG9c9PWPihY4ggMQNQSMtzU77CNgAJwmA==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-jmNYKe9MGGPoSl/D7JDDs1C8b3dC8f/w78LbaVfoTtWy4xAd5dfjaFG9c9PWPihY4ggMQNQSMtzU77CNgAJwmA==} + engines: {node: '>=18.0.0'} '@smithy/property-provider@4.2.8': - resolution: - { - integrity: sha512-EtCTbyIveCKeOXDSWSdze3k612yCPq1YbXsbqX3UHhkOSW8zKsM9NOJG5gTIya0vbY2DIaieG8pKo1rITHYL0w==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-EtCTbyIveCKeOXDSWSdze3k612yCPq1YbXsbqX3UHhkOSW8zKsM9NOJG5gTIya0vbY2DIaieG8pKo1rITHYL0w==} + engines: {node: '>=18.0.0'} '@smithy/protocol-http@5.3.7': - resolution: - { - integrity: sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA==} + engines: {node: '>=18.0.0'} '@smithy/protocol-http@5.3.8': - resolution: - { - integrity: sha512-QNINVDhxpZ5QnP3aviNHQFlRogQZDfYlCkQT+7tJnErPQbDhysondEjhikuANxgMsZrkGeiAxXy4jguEGsDrWQ==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-QNINVDhxpZ5QnP3aviNHQFlRogQZDfYlCkQT+7tJnErPQbDhysondEjhikuANxgMsZrkGeiAxXy4jguEGsDrWQ==} + engines: {node: '>=18.0.0'} '@smithy/querystring-builder@4.2.7': - resolution: - { - integrity: sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg==} + engines: {node: '>=18.0.0'} '@smithy/querystring-builder@4.2.8': - resolution: - { - integrity: sha512-Xr83r31+DrE8CP3MqPgMJl+pQlLLmOfiEUnoyAlGzzJIrEsbKsPy1hqH0qySaQm4oWrCBlUqRt+idEgunKB+iw==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-Xr83r31+DrE8CP3MqPgMJl+pQlLLmOfiEUnoyAlGzzJIrEsbKsPy1hqH0qySaQm4oWrCBlUqRt+idEgunKB+iw==} + engines: {node: '>=18.0.0'} '@smithy/querystring-parser@4.2.7': - resolution: - { - integrity: sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w==} + engines: {node: '>=18.0.0'} '@smithy/querystring-parser@4.2.8': - resolution: - { - integrity: sha512-vUurovluVy50CUlazOiXkPq40KGvGWSdmusa3130MwrR1UNnNgKAlj58wlOe61XSHRpUfIIh6cE0zZ8mzKaDPA==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-vUurovluVy50CUlazOiXkPq40KGvGWSdmusa3130MwrR1UNnNgKAlj58wlOe61XSHRpUfIIh6cE0zZ8mzKaDPA==} + engines: {node: '>=18.0.0'} '@smithy/service-error-classification@4.2.8': - resolution: - { - integrity: sha512-mZ5xddodpJhEt3RkCjbmUQuXUOaPNTkbMGR0bcS8FE0bJDLMZlhmpgrvPNCYglVw5rsYTpSnv19womw9WWXKQQ==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-mZ5xddodpJhEt3RkCjbmUQuXUOaPNTkbMGR0bcS8FE0bJDLMZlhmpgrvPNCYglVw5rsYTpSnv19womw9WWXKQQ==} + engines: {node: '>=18.0.0'} '@smithy/shared-ini-file-loader@4.4.2': - resolution: - { - integrity: sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg==} + engines: {node: '>=18.0.0'} '@smithy/shared-ini-file-loader@4.4.3': - resolution: - { - integrity: sha512-DfQjxXQnzC5UbCUPeC3Ie8u+rIWZTvuDPAGU/BxzrOGhRvgUanaP68kDZA+jaT3ZI+djOf+4dERGlm9mWfFDrg==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-DfQjxXQnzC5UbCUPeC3Ie8u+rIWZTvuDPAGU/BxzrOGhRvgUanaP68kDZA+jaT3ZI+djOf+4dERGlm9mWfFDrg==} + engines: {node: '>=18.0.0'} '@smithy/signature-v4@5.3.8': - resolution: - { - integrity: sha512-6A4vdGj7qKNRF16UIcO8HhHjKW27thsxYci+5r/uVRkdcBEkOEiY8OMPuydLX4QHSrJqGHPJzPRwwVTqbLZJhg==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-6A4vdGj7qKNRF16UIcO8HhHjKW27thsxYci+5r/uVRkdcBEkOEiY8OMPuydLX4QHSrJqGHPJzPRwwVTqbLZJhg==} + engines: {node: '>=18.0.0'} '@smithy/smithy-client@4.10.2': - resolution: - { - integrity: sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g==} + engines: {node: '>=18.0.0'} '@smithy/smithy-client@4.10.7': - resolution: - { - integrity: sha512-Uznt0I9z3os3Z+8pbXrOSCTXCA6vrjyN7Ub+8l2pRDum44vLv8qw0qGVkJN0/tZBZotaEFHrDPKUoPNueTr5Vg==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-Uznt0I9z3os3Z+8pbXrOSCTXCA6vrjyN7Ub+8l2pRDum44vLv8qw0qGVkJN0/tZBZotaEFHrDPKUoPNueTr5Vg==} + engines: {node: '>=18.0.0'} '@smithy/smithy-client@4.10.9': - resolution: - { - integrity: sha512-Je0EvGXVJ0Vrrr2lsubq43JGRIluJ/hX17aN/W/A0WfE+JpoMdI8kwk2t9F0zTX9232sJDGcoH4zZre6m6f/sg==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-Je0EvGXVJ0Vrrr2lsubq43JGRIluJ/hX17aN/W/A0WfE+JpoMdI8kwk2t9F0zTX9232sJDGcoH4zZre6m6f/sg==} + engines: {node: '>=18.0.0'} '@smithy/types@4.11.0': - resolution: - { - integrity: sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA==} + engines: {node: '>=18.0.0'} '@smithy/types@4.12.0': - resolution: - { - integrity: sha512-9YcuJVTOBDjg9LWo23Qp0lTQ3D7fQsQtwle0jVfpbUHy9qBwCEgKuVH4FqFB3VYu0nwdHKiEMA+oXz7oV8X1kw==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-9YcuJVTOBDjg9LWo23Qp0lTQ3D7fQsQtwle0jVfpbUHy9qBwCEgKuVH4FqFB3VYu0nwdHKiEMA+oXz7oV8X1kw==} + engines: {node: '>=18.0.0'} '@smithy/url-parser@4.2.7': - resolution: - { - integrity: sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg==} + engines: {node: '>=18.0.0'} '@smithy/url-parser@4.2.8': - resolution: - { - integrity: sha512-NQho9U68TGMEU639YkXnVMV3GEFFULmmaWdlu1E9qzyIePOHsoSnagTGSDv1Zi8DCNN6btxOSdgmy5E/hsZwhA==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-NQho9U68TGMEU639YkXnVMV3GEFFULmmaWdlu1E9qzyIePOHsoSnagTGSDv1Zi8DCNN6btxOSdgmy5E/hsZwhA==} + engines: {node: '>=18.0.0'} '@smithy/util-base64@4.3.0': - resolution: - { - integrity: sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ==} + engines: {node: '>=18.0.0'} '@smithy/util-body-length-browser@4.2.0': - resolution: - { - integrity: sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg==} + engines: {node: '>=18.0.0'} '@smithy/util-body-length-node@4.2.1': - resolution: - { - integrity: sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA==} + engines: {node: '>=18.0.0'} '@smithy/util-buffer-from@2.2.0': - resolution: - { - integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==, - } - engines: { node: '>=14.0.0' } + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} '@smithy/util-buffer-from@4.2.0': - resolution: - { - integrity: sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew==} + engines: {node: '>=18.0.0'} '@smithy/util-config-provider@4.2.0': - resolution: - { - integrity: sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q==} + engines: {node: '>=18.0.0'} '@smithy/util-defaults-mode-browser@4.3.21': - resolution: - { - integrity: sha512-DtmVJarzqtjghtGjCw/PFJolcJkP7GkZgy+hWTAN3YLXNH+IC82uMoMhFoC3ZtIz5mOgCm5+hOGi1wfhVYgrxw==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-DtmVJarzqtjghtGjCw/PFJolcJkP7GkZgy+hWTAN3YLXNH+IC82uMoMhFoC3ZtIz5mOgCm5+hOGi1wfhVYgrxw==} + engines: {node: '>=18.0.0'} '@smithy/util-defaults-mode-browser@4.3.23': - resolution: - { - integrity: sha512-mMg+r/qDfjfF/0psMbV4zd7F/i+rpyp7Hjh0Wry7eY15UnzTEId+xmQTGDU8IdZtDfbGQxuWNfgBZKBj+WuYbA==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-mMg+r/qDfjfF/0psMbV4zd7F/i+rpyp7Hjh0Wry7eY15UnzTEId+xmQTGDU8IdZtDfbGQxuWNfgBZKBj+WuYbA==} + engines: {node: '>=18.0.0'} '@smithy/util-defaults-mode-node@4.2.24': - resolution: - { - integrity: sha512-JelBDKPAVswVY666rezBvY6b0nF/v9TXjUbNwDNAyme7qqKYEX687wJv0uze8lBIZVbg30wlWnlYfVSjjpKYFA==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-JelBDKPAVswVY666rezBvY6b0nF/v9TXjUbNwDNAyme7qqKYEX687wJv0uze8lBIZVbg30wlWnlYfVSjjpKYFA==} + engines: {node: '>=18.0.0'} '@smithy/util-defaults-mode-node@4.2.26': - resolution: - { - integrity: sha512-EQqe/WkbCinah0h1lMWh9ICl0Ob4lyl20/10WTB35SC9vDQfD8zWsOT+x2FIOXKAoZQ8z/y0EFMoodbcqWJY/w==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-EQqe/WkbCinah0h1lMWh9ICl0Ob4lyl20/10WTB35SC9vDQfD8zWsOT+x2FIOXKAoZQ8z/y0EFMoodbcqWJY/w==} + engines: {node: '>=18.0.0'} '@smithy/util-endpoints@3.2.8': - resolution: - { - integrity: sha512-8JaVTn3pBDkhZgHQ8R0epwWt+BqPSLCjdjXXusK1onwJlRuN69fbvSK66aIKKO7SwVFM6x2J2ox5X8pOaWcUEw==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-8JaVTn3pBDkhZgHQ8R0epwWt+BqPSLCjdjXXusK1onwJlRuN69fbvSK66aIKKO7SwVFM6x2J2ox5X8pOaWcUEw==} + engines: {node: '>=18.0.0'} '@smithy/util-hex-encoding@4.2.0': - resolution: - { - integrity: sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw==} + engines: {node: '>=18.0.0'} '@smithy/util-middleware@4.2.7': - resolution: - { - integrity: sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w==} + engines: {node: '>=18.0.0'} '@smithy/util-middleware@4.2.8': - resolution: - { - integrity: sha512-PMqfeJxLcNPMDgvPbbLl/2Vpin+luxqTGPpW3NAQVLbRrFRzTa4rNAASYeIGjRV9Ytuhzny39SpyU04EQreF+A==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-PMqfeJxLcNPMDgvPbbLl/2Vpin+luxqTGPpW3NAQVLbRrFRzTa4rNAASYeIGjRV9Ytuhzny39SpyU04EQreF+A==} + engines: {node: '>=18.0.0'} '@smithy/util-retry@4.2.8': - resolution: - { - integrity: sha512-CfJqwvoRY0kTGe5AkQokpURNCT1u/MkRzMTASWMPPo2hNSnKtF1D45dQl3DE2LKLr4m+PW9mCeBMJr5mCAVThg==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-CfJqwvoRY0kTGe5AkQokpURNCT1u/MkRzMTASWMPPo2hNSnKtF1D45dQl3DE2LKLr4m+PW9mCeBMJr5mCAVThg==} + engines: {node: '>=18.0.0'} '@smithy/util-stream@4.5.10': - resolution: - { - integrity: sha512-jbqemy51UFSZSp2y0ZmRfckmrzuKww95zT9BYMmuJ8v3altGcqjwoV1tzpOwuHaKrwQrCjIzOib499ymr2f98g==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-jbqemy51UFSZSp2y0ZmRfckmrzuKww95zT9BYMmuJ8v3altGcqjwoV1tzpOwuHaKrwQrCjIzOib499ymr2f98g==} + engines: {node: '>=18.0.0'} '@smithy/util-stream@4.5.8': - resolution: - { - integrity: sha512-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w==} + engines: {node: '>=18.0.0'} '@smithy/util-uri-escape@4.2.0': - resolution: - { - integrity: sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA==} + engines: {node: '>=18.0.0'} '@smithy/util-utf8@2.3.0': - resolution: - { - integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==, - } - engines: { node: '>=14.0.0' } + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} '@smithy/util-utf8@4.2.0': - resolution: - { - integrity: sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==} + engines: {node: '>=18.0.0'} '@smithy/util-waiter@4.2.8': - resolution: - { - integrity: sha512-n+lahlMWk+aejGuax7DPWtqav8HYnWxQwR+LCG2BgCUmaGcTe9qZCFsmw8TMg9iG75HOwhrJCX9TCJRLH+Yzqg==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-n+lahlMWk+aejGuax7DPWtqav8HYnWxQwR+LCG2BgCUmaGcTe9qZCFsmw8TMg9iG75HOwhrJCX9TCJRLH+Yzqg==} + engines: {node: '>=18.0.0'} '@smithy/uuid@1.1.0': - resolution: - { - integrity: sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==} + engines: {node: '>=18.0.0'} '@styled-system/background@5.1.2': - resolution: - { - integrity: sha512-jtwH2C/U6ssuGSvwTN3ri/IyjdHb8W9X/g8Y0JLcrH02G+BW3OS8kZdHphF1/YyRklnrKrBT2ngwGUK6aqqV3A==, - } + resolution: {integrity: sha512-jtwH2C/U6ssuGSvwTN3ri/IyjdHb8W9X/g8Y0JLcrH02G+BW3OS8kZdHphF1/YyRklnrKrBT2ngwGUK6aqqV3A==} '@styled-system/border@5.1.5': - resolution: - { - integrity: sha512-JvddhNrnhGigtzWRCVuAHepniyVi6hBlimxWDVAdcTuk7aRn9BYJUwfHslURtwYFsF5FoEs8Zmr1oZq2M1AP0A==, - } + resolution: {integrity: sha512-JvddhNrnhGigtzWRCVuAHepniyVi6hBlimxWDVAdcTuk7aRn9BYJUwfHslURtwYFsF5FoEs8Zmr1oZq2M1AP0A==} '@styled-system/color@5.1.2': - resolution: - { - integrity: sha512-1kCkeKDZkt4GYkuFNKc7vJQMcOmTl3bJY3YBUs7fCNM6mMYJeT1pViQ2LwBSBJytj3AB0o4IdLBoepgSgGl5MA==, - } + resolution: {integrity: sha512-1kCkeKDZkt4GYkuFNKc7vJQMcOmTl3bJY3YBUs7fCNM6mMYJeT1pViQ2LwBSBJytj3AB0o4IdLBoepgSgGl5MA==} '@styled-system/core@5.1.2': - resolution: - { - integrity: sha512-XclBDdNIy7OPOsN4HBsawG2eiWfCcuFt6gxKn1x4QfMIgeO6TOlA2pZZ5GWZtIhCUqEPTgIBta6JXsGyCkLBYw==, - } + resolution: {integrity: sha512-XclBDdNIy7OPOsN4HBsawG2eiWfCcuFt6gxKn1x4QfMIgeO6TOlA2pZZ5GWZtIhCUqEPTgIBta6JXsGyCkLBYw==} '@styled-system/css@5.1.5': - resolution: - { - integrity: sha512-XkORZdS5kypzcBotAMPBoeckDs9aSZVkvrAlq5K3xP8IMAUek+x2O4NtwoSgkYkWWzVBu6DGdFZLR790QWGG+A==, - } + resolution: {integrity: sha512-XkORZdS5kypzcBotAMPBoeckDs9aSZVkvrAlq5K3xP8IMAUek+x2O4NtwoSgkYkWWzVBu6DGdFZLR790QWGG+A==} '@styled-system/flexbox@5.1.2': - resolution: - { - integrity: sha512-6hHV52+eUk654Y1J2v77B8iLeBNtc+SA3R4necsu2VVinSD7+XY5PCCEzBFaWs42dtOEDIa2lMrgL0YBC01mDQ==, - } + resolution: {integrity: sha512-6hHV52+eUk654Y1J2v77B8iLeBNtc+SA3R4necsu2VVinSD7+XY5PCCEzBFaWs42dtOEDIa2lMrgL0YBC01mDQ==} '@styled-system/grid@5.1.2': - resolution: - { - integrity: sha512-K3YiV1KyHHzgdNuNlaw8oW2ktMuGga99o1e/NAfTEi5Zsa7JXxzwEnVSDSBdJC+z6R8WYTCYRQC6bkVFcvdTeg==, - } + resolution: {integrity: sha512-K3YiV1KyHHzgdNuNlaw8oW2ktMuGga99o1e/NAfTEi5Zsa7JXxzwEnVSDSBdJC+z6R8WYTCYRQC6bkVFcvdTeg==} '@styled-system/layout@5.1.2': - resolution: - { - integrity: sha512-wUhkMBqSeacPFhoE9S6UF3fsMEKFv91gF4AdDWp0Aym1yeMPpqz9l9qS/6vjSsDPF7zOb5cOKC3tcKKOMuDCPw==, - } + resolution: {integrity: sha512-wUhkMBqSeacPFhoE9S6UF3fsMEKFv91gF4AdDWp0Aym1yeMPpqz9l9qS/6vjSsDPF7zOb5cOKC3tcKKOMuDCPw==} '@styled-system/position@5.1.2': - resolution: - { - integrity: sha512-60IZfMXEOOZe3l1mCu6sj/2NAyUmES2kR9Kzp7s2D3P4qKsZWxD1Se1+wJvevb+1TP+ZMkGPEYYXRyU8M1aF5A==, - } + resolution: {integrity: sha512-60IZfMXEOOZe3l1mCu6sj/2NAyUmES2kR9Kzp7s2D3P4qKsZWxD1Se1+wJvevb+1TP+ZMkGPEYYXRyU8M1aF5A==} '@styled-system/shadow@5.1.2': - resolution: - { - integrity: sha512-wqniqYb7XuZM7K7C0d1Euxc4eGtqEe/lvM0WjuAFsQVImiq6KGT7s7is+0bNI8O4Dwg27jyu4Lfqo/oIQXNzAg==, - } + resolution: {integrity: sha512-wqniqYb7XuZM7K7C0d1Euxc4eGtqEe/lvM0WjuAFsQVImiq6KGT7s7is+0bNI8O4Dwg27jyu4Lfqo/oIQXNzAg==} '@styled-system/space@5.1.2': - resolution: - { - integrity: sha512-+zzYpR8uvfhcAbaPXhH8QgDAV//flxqxSjHiS9cDFQQUSznXMQmxJegbhcdEF7/eNnJgHeIXv1jmny78kipgBA==, - } + resolution: {integrity: sha512-+zzYpR8uvfhcAbaPXhH8QgDAV//flxqxSjHiS9cDFQQUSznXMQmxJegbhcdEF7/eNnJgHeIXv1jmny78kipgBA==} '@styled-system/typography@5.1.2': - resolution: - { - integrity: sha512-BxbVUnN8N7hJ4aaPOd7wEsudeT7CxarR+2hns8XCX1zp0DFfbWw4xYa/olA0oQaqx7F1hzDg+eRaGzAJbF+jOg==, - } + resolution: {integrity: sha512-BxbVUnN8N7hJ4aaPOd7wEsudeT7CxarR+2hns8XCX1zp0DFfbWw4xYa/olA0oQaqx7F1hzDg+eRaGzAJbF+jOg==} '@styled-system/variant@5.1.5': - resolution: - { - integrity: sha512-Yn8hXAFoWIro8+Q5J8YJd/mP85Teiut3fsGVR9CAxwgNfIAiqlYxsk5iHU7VHJks/0KjL4ATSjmbtCDC/4l1qw==, - } + resolution: {integrity: sha512-Yn8hXAFoWIro8+Q5J8YJd/mP85Teiut3fsGVR9CAxwgNfIAiqlYxsk5iHU7VHJks/0KjL4ATSjmbtCDC/4l1qw==} '@tanstack/query-core@5.90.19': - resolution: - { - integrity: sha512-GLW5sjPVIvH491VV1ufddnfldyVB+teCnpPIvweEfkpRx7CfUmUGhoh9cdcUKBh/KwVxk22aNEDxeTsvmyB/WA==, - } + resolution: {integrity: sha512-GLW5sjPVIvH491VV1ufddnfldyVB+teCnpPIvweEfkpRx7CfUmUGhoh9cdcUKBh/KwVxk22aNEDxeTsvmyB/WA==} + + '@tanstack/query-core@5.90.20': + resolution: {integrity: sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==} '@tanstack/react-query@5.90.19': - resolution: - { - integrity: sha512-qTZRZ4QyTzQc+M0IzrbKHxSeISUmRB3RPGmao5bT+sI6ayxSRhn0FXEnT5Hg3as8SBFcRosrXXRFB+yAcxVxJQ==, - } + resolution: {integrity: sha512-qTZRZ4QyTzQc+M0IzrbKHxSeISUmRB3RPGmao5bT+sI6ayxSRhn0FXEnT5Hg3as8SBFcRosrXXRFB+yAcxVxJQ==} + peerDependencies: + react: ^18 || ^19 + + '@tanstack/react-query@5.90.20': + resolution: {integrity: sha512-vXBxa+qeyveVO7OA0jX1z+DeyCA4JKnThKv411jd5SORpBKgkcVnYKCiBgECvADvniBX7tobwBmg01qq9JmMJw==} peerDependencies: react: ^18 || ^19 '@testing-library/dom@7.31.2': - resolution: - { - integrity: sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==} + engines: {node: '>=10'} '@testing-library/jest-dom@5.11.10': - resolution: - { - integrity: sha512-FuKiq5xuk44Fqm0000Z9w0hjOdwZRNzgx7xGGxQYepWFZy+OYUMOT/wPI4nLYXCaVltNVpU1W/qmD88wLWDsqQ==, - } - engines: { node: '>=8', npm: '>=6', yarn: '>=1' } + resolution: {integrity: sha512-FuKiq5xuk44Fqm0000Z9w0hjOdwZRNzgx7xGGxQYepWFZy+OYUMOT/wPI4nLYXCaVltNVpU1W/qmD88wLWDsqQ==} + engines: {node: '>=8', npm: '>=6', yarn: '>=1'} '@testing-library/react@11.2.5': - resolution: - { - integrity: sha512-yEx7oIa/UWLe2F2dqK0FtMF9sJWNXD+2PPtp39BvE0Kh9MJ9Kl0HrZAgEuhUJR+Lx8Di6Xz+rKwSdEPY2UV8ZQ==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-yEx7oIa/UWLe2F2dqK0FtMF9sJWNXD+2PPtp39BvE0Kh9MJ9Kl0HrZAgEuhUJR+Lx8Di6Xz+rKwSdEPY2UV8ZQ==} + engines: {node: '>=10'} peerDependencies: react: '*' react-dom: '*' '@tsconfig/node10@1.0.12': - resolution: - { - integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==, - } + resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==} '@tsconfig/node12@1.0.11': - resolution: - { - integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==, - } + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} '@tsconfig/node14@1.0.3': - resolution: - { - integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==, - } + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} '@tsconfig/node16@1.0.4': - resolution: - { - integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==, - } + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} '@tufjs/canonical-json@2.0.0': - resolution: - { - integrity: sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==} + engines: {node: ^16.14.0 || >=18.0.0} '@tufjs/models@2.0.1': - resolution: - { - integrity: sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==} + engines: {node: ^16.14.0 || >=18.0.0} '@tybys/wasm-util@0.10.1': - resolution: - { - integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==, - } + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} '@tybys/wasm-util@0.9.0': - resolution: - { - integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==, - } + resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} '@types/accept-language-parser@1.5.8': - resolution: - { - integrity: sha512-6+dKdh9q/I8xDBnKQKddCBKaWBWLmJ97HTiSbAXVpL7LEgDfOkKF98UVCaZ5KJrtdN5Wa5ndXUiqD3XR9XGqWQ==, - } + resolution: {integrity: sha512-6+dKdh9q/I8xDBnKQKddCBKaWBWLmJ97HTiSbAXVpL7LEgDfOkKF98UVCaZ5KJrtdN5Wa5ndXUiqD3XR9XGqWQ==} '@types/accepts@1.3.7': - resolution: - { - integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==, - } + resolution: {integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==} '@types/aria-query@4.2.2': - resolution: - { - integrity: sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==, - } + resolution: {integrity: sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==} '@types/babel__core@7.20.5': - resolution: - { - integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==, - } + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} '@types/babel__generator@7.27.0': - resolution: - { - integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==, - } + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} '@types/babel__template@7.4.4': - resolution: - { - integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==, - } + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} '@types/babel__traverse@7.28.0': - resolution: - { - integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==, - } + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} '@types/body-parser@1.19.6': - resolution: - { - integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==, - } + resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} '@types/connect@3.4.38': - resolution: - { - integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==, - } + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} '@types/content-disposition@0.5.9': - resolution: - { - integrity: sha512-8uYXI3Gw35MhiVYhG3s295oihrxRyytcRHjSjqnqZVDDy/xcGBRny7+Xj1Wgfhv5QzRtN2hB2dVRBUX9XW3UcQ==, - } + resolution: {integrity: sha512-8uYXI3Gw35MhiVYhG3s295oihrxRyytcRHjSjqnqZVDDy/xcGBRny7+Xj1Wgfhv5QzRtN2hB2dVRBUX9XW3UcQ==} '@types/cookiejar@2.1.5': - resolution: - { - integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==, - } + resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} '@types/cookies@0.9.2': - resolution: - { - integrity: sha512-1AvkDdZM2dbyFybL4fxpuNCaWyv//0AwsuUk2DWeXyM1/5ZKm6W3z6mQi24RZ4l2ucY+bkSHzbDVpySqPGuV8A==, - } + resolution: {integrity: sha512-1AvkDdZM2dbyFybL4fxpuNCaWyv//0AwsuUk2DWeXyM1/5ZKm6W3z6mQi24RZ4l2ucY+bkSHzbDVpySqPGuV8A==} '@types/cors@2.8.19': - resolution: - { - integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==, - } + resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==} '@types/estree@1.0.8': - resolution: - { - integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==, - } + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} '@types/express-serve-static-core@5.1.0': - resolution: - { - integrity: sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==, - } + resolution: {integrity: sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==} '@types/express@5.0.6': - resolution: - { - integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==, - } + resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==} '@types/geojson@7946.0.16': - resolution: - { - integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==, - } + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} '@types/graphql-upload@8.0.12': - resolution: - { - integrity: sha512-M0ZPZqNUzKNB16q5woEzgG/Q8DjICV80K7JvDSRnDmDFfrRdfFX/n6PbmqAN7gCzECcHVnw1gk6N4Cg0FwxCqA==, - } + resolution: {integrity: sha512-M0ZPZqNUzKNB16q5woEzgG/Q8DjICV80K7JvDSRnDmDFfrRdfFX/n6PbmqAN7gCzECcHVnw1gk6N4Cg0FwxCqA==} '@types/http-assert@1.5.6': - resolution: - { - integrity: sha512-TTEwmtjgVbYAzZYWyeHPrrtWnfVkm8tQkP8P21uQifPgMRgjrow3XDEYqucuC8SKZJT7pUnhU/JymvjggxO9vw==, - } + resolution: {integrity: sha512-TTEwmtjgVbYAzZYWyeHPrrtWnfVkm8tQkP8P21uQifPgMRgjrow3XDEYqucuC8SKZJT7pUnhU/JymvjggxO9vw==} '@types/http-errors@2.0.5': - resolution: - { - integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==, - } + resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} '@types/istanbul-lib-coverage@2.0.6': - resolution: - { - integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==, - } + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} '@types/istanbul-lib-report@3.0.3': - resolution: - { - integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==, - } + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} '@types/istanbul-reports@3.0.4': - resolution: - { - integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==, - } + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} '@types/jest-in-case@1.0.9': - resolution: - { - integrity: sha512-tapHpzWGjCC/hxYJyzbJ/5ZV6rA2153Sve5lGJUAIA1Jzrphfp27TznAWfGeXf+d8TLN7zMujaC0UwNQwSJaQg==, - } + resolution: {integrity: sha512-tapHpzWGjCC/hxYJyzbJ/5ZV6rA2153Sve5lGJUAIA1Jzrphfp27TznAWfGeXf+d8TLN7zMujaC0UwNQwSJaQg==} '@types/jest@30.0.0': - resolution: - { - integrity: sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==, - } + resolution: {integrity: sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==} '@types/js-yaml@4.0.9': - resolution: - { - integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==, - } + resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} '@types/json-schema@7.0.15': - resolution: - { - integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==, - } + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} '@types/json5@0.0.30': - resolution: - { - integrity: sha512-sqm9g7mHlPY/43fcSNrCYfOeX9zkTTK+euO5E6+CVijSMm5tTjkVdwdqRkY3ljjIAf8679vps5jKUoJBCLsMDA==, - } + resolution: {integrity: sha512-sqm9g7mHlPY/43fcSNrCYfOeX9zkTTK+euO5E6+CVijSMm5tTjkVdwdqRkY3ljjIAf8679vps5jKUoJBCLsMDA==} '@types/jsonwebtoken@9.0.10': - resolution: - { - integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==, - } + resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==} '@types/keygrip@1.0.6': - resolution: - { - integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==, - } + resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==} '@types/koa-compose@3.2.9': - resolution: - { - integrity: sha512-BroAZ9FTvPiCy0Pi8tjD1OfJ7bgU1gQf0eR6e1Vm+JJATy9eKOG3hQMFtMciMawiSOVnLMdmUOC46s7HBhSTsA==, - } + resolution: {integrity: sha512-BroAZ9FTvPiCy0Pi8tjD1OfJ7bgU1gQf0eR6e1Vm+JJATy9eKOG3hQMFtMciMawiSOVnLMdmUOC46s7HBhSTsA==} '@types/koa@3.0.1': - resolution: - { - integrity: sha512-VkB6WJUQSe0zBpR+Q7/YIUESGp5wPHcaXr0xueU5W0EOUWtlSbblsl+Kl31lyRQ63nIILh0e/7gXjQ09JXJIHw==, - } + resolution: {integrity: sha512-VkB6WJUQSe0zBpR+Q7/YIUESGp5wPHcaXr0xueU5W0EOUWtlSbblsl+Kl31lyRQ63nIILh0e/7gXjQ09JXJIHw==} '@types/methods@1.1.4': - resolution: - { - integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==, - } + resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==} '@types/minimatch@3.0.5': - resolution: - { - integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==, - } + resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} '@types/minimist@1.2.5': - resolution: - { - integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==, - } + resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} '@types/ms@2.1.0': - resolution: - { - integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==, - } + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} '@types/node@18.19.130': - resolution: - { - integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==, - } + resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} '@types/node@20.19.27': - resolution: - { - integrity: sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==, - } + resolution: {integrity: sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==} '@types/nodemailer@7.0.5': - resolution: - { - integrity: sha512-7WtR4MFJUNN2UFy0NIowBRJswj5KXjXDhlZY43Hmots5eGu5q/dTeFd/I6GgJA/qj3RqO6dDy4SvfcV3fOVeIA==, - } + resolution: {integrity: sha512-7WtR4MFJUNN2UFy0NIowBRJswj5KXjXDhlZY43Hmots5eGu5q/dTeFd/I6GgJA/qj3RqO6dDy4SvfcV3fOVeIA==} '@types/normalize-package-data@2.4.4': - resolution: - { - integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==, - } + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} '@types/pg-copy-streams@1.2.5': - resolution: - { - integrity: sha512-7D6/GYW2uHIaVU6S/5omI+6RZnwlZBpLQDZAH83xX1rjxAOK0f6/deKyyUTewxqts145VIGn6XWYz1YGf50G5g==, - } + resolution: {integrity: sha512-7D6/GYW2uHIaVU6S/5omI+6RZnwlZBpLQDZAH83xX1rjxAOK0f6/deKyyUTewxqts145VIGn6XWYz1YGf50G5g==} '@types/pg@8.16.0': - resolution: - { - integrity: sha512-RmhMd/wD+CF8Dfo+cVIy3RR5cl8CyfXQ0tGgW6XBL8L4LM/UTEbNXYRbLwU6w+CgrKBNbrQWt4FUtTfaU5jSYQ==, - } + resolution: {integrity: sha512-RmhMd/wD+CF8Dfo+cVIy3RR5cl8CyfXQ0tGgW6XBL8L4LM/UTEbNXYRbLwU6w+CgrKBNbrQWt4FUtTfaU5jSYQ==} '@types/qs@6.14.0': - resolution: - { - integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==, - } + resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} '@types/range-parser@1.2.7': - resolution: - { - integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==, - } + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.13': + resolution: {integrity: sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==} '@types/react@19.2.8': - resolution: - { - integrity: sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==, - } + resolution: {integrity: sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==} '@types/request-ip@0.0.41': - resolution: - { - integrity: sha512-Qzz0PM2nSZej4lsLzzNfADIORZhhxO7PED0fXpg4FjXiHuJ/lMyUg+YFF5q8x9HPZH3Gl6N+NOM8QZjItNgGKg==, - } + resolution: {integrity: sha512-Qzz0PM2nSZej4lsLzzNfADIORZhhxO7PED0fXpg4FjXiHuJ/lMyUg+YFF5q8x9HPZH3Gl6N+NOM8QZjItNgGKg==} '@types/semver@7.7.1': - resolution: - { - integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==, - } + resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} '@types/send@1.2.1': - resolution: - { - integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==, - } + resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} '@types/serve-static@2.2.0': - resolution: - { - integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==, - } + resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} '@types/shelljs@0.8.17': - resolution: - { - integrity: sha512-IDksKYmQA2W9MkQjiyptbMmcQx+8+Ol6b7h6dPU5S05JyiQDSb/nZKnrMrZqGwgV6VkVdl6/SPCKPDlMRvqECg==, - } + resolution: {integrity: sha512-IDksKYmQA2W9MkQjiyptbMmcQx+8+Ol6b7h6dPU5S05JyiQDSb/nZKnrMrZqGwgV6VkVdl6/SPCKPDlMRvqECg==} '@types/smtp-server@3.5.12': - resolution: - { - integrity: sha512-IBemrqI6nzvbgwE41Lnd4v4Yf1Kc7F1UHjk1GFBLNhLcI/Zop1ggHQ8g7Y8QYc6jGVgzWQcsa0MBNcGnDY9UGw==, - } + resolution: {integrity: sha512-IBemrqI6nzvbgwE41Lnd4v4Yf1Kc7F1UHjk1GFBLNhLcI/Zop1ggHQ8g7Y8QYc6jGVgzWQcsa0MBNcGnDY9UGw==} '@types/stack-utils@2.0.3': - resolution: - { - integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==, - } + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} '@types/superagent@8.1.9': - resolution: - { - integrity: sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==, - } + resolution: {integrity: sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==} '@types/supertest@6.0.3': - resolution: - { - integrity: sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==, - } + resolution: {integrity: sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==} '@types/testing-library__jest-dom@5.14.9': - resolution: - { - integrity: sha512-FSYhIjFlfOpGSRyVoMBMuS3ws5ehFQODymf3vlI7U1K8c7PHwWwFY7VREfmsuzHSOnoKs/9/Y983ayOs7eRzqw==, - } + resolution: {integrity: sha512-FSYhIjFlfOpGSRyVoMBMuS3ws5ehFQODymf3vlI7U1K8c7PHwWwFY7VREfmsuzHSOnoKs/9/Y983ayOs7eRzqw==} '@types/ws@7.4.7': - resolution: - { - integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==, - } + resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} '@types/yargs-parser@21.0.3': - resolution: - { - integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==, - } + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} '@types/yargs@15.0.20': - resolution: - { - integrity: sha512-KIkX+/GgfFitlASYCGoSF+T4XRXhOubJLhkLVtSfsRTe9jWMmuM2g28zQ41BtPTG7TRBb2xHW+LCNVE9QR/vsg==, - } + resolution: {integrity: sha512-KIkX+/GgfFitlASYCGoSF+T4XRXhOubJLhkLVtSfsRTe9jWMmuM2g28zQ41BtPTG7TRBb2xHW+LCNVE9QR/vsg==} '@types/yargs@17.0.35': - resolution: - { - integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==, - } + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} '@typescript-eslint/eslint-plugin@8.53.1': - resolution: - { - integrity: sha512-cFYYFZ+oQFi6hUnBTbLRXfTJiaQtYE3t4O692agbBl+2Zy+eqSKWtPjhPXJu1G7j4RLjKgeJPDdq3EqOwmX5Ag==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-cFYYFZ+oQFi6hUnBTbLRXfTJiaQtYE3t4O692agbBl+2Zy+eqSKWtPjhPXJu1G7j4RLjKgeJPDdq3EqOwmX5Ag==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.53.1 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' '@typescript-eslint/parser@8.53.1': - resolution: - { - integrity: sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' '@typescript-eslint/project-service@8.53.1': - resolution: - { - integrity: sha512-WYC4FB5Ra0xidsmlPb+1SsnaSKPmS3gsjIARwbEkHkoWloQmuzcfypljaJcR78uyLA1h8sHdWWPHSLDI+MtNog==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-WYC4FB5Ra0xidsmlPb+1SsnaSKPmS3gsjIARwbEkHkoWloQmuzcfypljaJcR78uyLA1h8sHdWWPHSLDI+MtNog==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' '@typescript-eslint/scope-manager@8.53.1': - resolution: - { - integrity: sha512-Lu23yw1uJMFY8cUeq7JlrizAgeQvWugNQzJp8C3x8Eo5Jw5Q2ykMdiiTB9vBVOOUBysMzmRRmUfwFrZuI2C4SQ==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-Lu23yw1uJMFY8cUeq7JlrizAgeQvWugNQzJp8C3x8Eo5Jw5Q2ykMdiiTB9vBVOOUBysMzmRRmUfwFrZuI2C4SQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/tsconfig-utils@8.53.1': - resolution: - { - integrity: sha512-qfvLXS6F6b1y43pnf0pPbXJ+YoXIC7HKg0UGZ27uMIemKMKA6XH2DTxsEDdpdN29D+vHV07x/pnlPNVLhdhWiA==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-qfvLXS6F6b1y43pnf0pPbXJ+YoXIC7HKg0UGZ27uMIemKMKA6XH2DTxsEDdpdN29D+vHV07x/pnlPNVLhdhWiA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' '@typescript-eslint/type-utils@8.53.1': - resolution: - { - integrity: sha512-MOrdtNvyhy0rHyv0ENzub1d4wQYKb2NmIqG7qEqPWFW7Mpy2jzFC3pQ2yKDvirZB7jypm5uGjF2Qqs6OIqu47w==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-MOrdtNvyhy0rHyv0ENzub1d4wQYKb2NmIqG7qEqPWFW7Mpy2jzFC3pQ2yKDvirZB7jypm5uGjF2Qqs6OIqu47w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' '@typescript-eslint/types@8.53.1': - resolution: - { - integrity: sha512-jr/swrr2aRmUAUjW5/zQHbMaui//vQlsZcJKijZf3M26bnmLj8LyZUpj8/Rd6uzaek06OWsqdofN/Thenm5O8A==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-jr/swrr2aRmUAUjW5/zQHbMaui//vQlsZcJKijZf3M26bnmLj8LyZUpj8/Rd6uzaek06OWsqdofN/Thenm5O8A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/typescript-estree@8.53.1': - resolution: - { - integrity: sha512-RGlVipGhQAG4GxV1s34O91cxQ/vWiHJTDHbXRr0li2q/BGg3RR/7NM8QDWgkEgrwQYCvmJV9ichIwyoKCQ+DTg==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-RGlVipGhQAG4GxV1s34O91cxQ/vWiHJTDHbXRr0li2q/BGg3RR/7NM8QDWgkEgrwQYCvmJV9ichIwyoKCQ+DTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' '@typescript-eslint/utils@8.53.1': - resolution: - { - integrity: sha512-c4bMvGVWW4hv6JmDUEG7fSYlWOl3II2I4ylt0NM+seinYQlZMQIaKaXIIVJWt9Ofh6whrpM+EdDQXKXjNovvrg==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-c4bMvGVWW4hv6JmDUEG7fSYlWOl3II2I4ylt0NM+seinYQlZMQIaKaXIIVJWt9Ofh6whrpM+EdDQXKXjNovvrg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' '@typescript-eslint/visitor-keys@8.53.1': - resolution: - { - integrity: sha512-oy+wV7xDKFPRyNggmXuZQSBzvoLnpmJs+GhzRhPjrxl2b/jIlyjVokzm47CZCDUdXKr2zd7ZLodPfOBpOPyPlg==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-oy+wV7xDKFPRyNggmXuZQSBzvoLnpmJs+GhzRhPjrxl2b/jIlyjVokzm47CZCDUdXKr2zd7ZLodPfOBpOPyPlg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.0': - resolution: - { - integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==, - } + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} '@unrs/resolver-binding-android-arm-eabi@1.11.1': - resolution: - { - integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==, - } + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} cpu: [arm] os: [android] '@unrs/resolver-binding-android-arm64@1.11.1': - resolution: - { - integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==, - } + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} cpu: [arm64] os: [android] '@unrs/resolver-binding-darwin-arm64@1.11.1': - resolution: - { - integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==, - } + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} cpu: [arm64] os: [darwin] '@unrs/resolver-binding-darwin-x64@1.11.1': - resolution: - { - integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==, - } + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} cpu: [x64] os: [darwin] '@unrs/resolver-binding-freebsd-x64@1.11.1': - resolution: - { - integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==, - } + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} cpu: [x64] os: [freebsd] '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': - resolution: - { - integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==, - } + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} cpu: [arm] os: [linux] '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': - resolution: - { - integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==, - } + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} cpu: [arm] os: [linux] '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': - resolution: - { - integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==, - } + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} cpu: [arm64] os: [linux] '@unrs/resolver-binding-linux-arm64-musl@1.11.1': - resolution: - { - integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==, - } + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} cpu: [arm64] os: [linux] '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': - resolution: - { - integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==, - } + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} cpu: [ppc64] os: [linux] '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': - resolution: - { - integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==, - } + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} cpu: [riscv64] os: [linux] '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': - resolution: - { - integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==, - } + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} cpu: [riscv64] os: [linux] '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': - resolution: - { - integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==, - } + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} cpu: [s390x] os: [linux] '@unrs/resolver-binding-linux-x64-gnu@1.11.1': - resolution: - { - integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==, - } + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} cpu: [x64] os: [linux] '@unrs/resolver-binding-linux-x64-musl@1.11.1': - resolution: - { - integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==, - } + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} cpu: [x64] os: [linux] '@unrs/resolver-binding-wasm32-wasi@1.11.1': - resolution: - { - integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==, - } - engines: { node: '>=14.0.0' } + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} cpu: [wasm32] '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': - resolution: - { - integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==, - } + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} cpu: [arm64] os: [win32] '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': - resolution: - { - integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==, - } + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} cpu: [ia32] os: [win32] '@unrs/resolver-binding-win32-x64-msvc@1.11.1': - resolution: - { - integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==, - } + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} cpu: [x64] os: [win32] + '@vitejs/plugin-react@4.7.0': + resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + '@yarnpkg/lockfile@1.1.0': - resolution: - { - integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==, - } + resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} '@yarnpkg/parsers@3.0.2': - resolution: - { - integrity: sha512-/HcYgtUSiJiot/XWGLOlGxPYUG65+/31V8oqk17vZLW1xlCoR4PampyePljOxY2n8/3jz9+tIFzICsyGujJZoA==, - } - engines: { node: '>=18.12.0' } + resolution: {integrity: sha512-/HcYgtUSiJiot/XWGLOlGxPYUG65+/31V8oqk17vZLW1xlCoR4PampyePljOxY2n8/3jz9+tIFzICsyGujJZoA==} + engines: {node: '>=18.12.0'} '@zkochan/js-yaml@0.0.7': - resolution: - { - integrity: sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==, - } + resolution: {integrity: sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==} hasBin: true JSONStream@1.3.5: - resolution: - { - integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==, - } + resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} hasBin: true abbrev@2.0.0: - resolution: - { - integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} accept-language-parser@1.5.0: - resolution: - { - integrity: sha512-QhyTbMLYo0BBGg1aWbeMG4ekWtds/31BrEU+DONOg/7ax23vxpL03Pb7/zBmha2v7vdD3AyzZVWBVGEZxKOXWw==, - } + resolution: {integrity: sha512-QhyTbMLYo0BBGg1aWbeMG4ekWtds/31BrEU+DONOg/7ax23vxpL03Pb7/zBmha2v7vdD3AyzZVWBVGEZxKOXWw==} accepts@2.0.0: - resolution: - { - integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==, - } - engines: { node: '>= 0.6' } + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} acorn-jsx@5.3.2: - resolution: - { - integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, - } + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 acorn-walk@8.3.4: - resolution: - { - integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==, - } - engines: { node: '>=0.4.0' } + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} acorn@8.15.0: - resolution: - { - integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==, - } - engines: { node: '>=0.4.0' } + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} hasBin: true add-stream@1.0.0: - resolution: - { - integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==, - } + resolution: {integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==} agent-base@7.1.4: - resolution: - { - integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==, - } - engines: { node: '>= 14' } + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} aggregate-error@3.1.0: - resolution: - { - integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} ajv@6.12.6: - resolution: - { - integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==, - } + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} ajv@7.2.4: - resolution: - { - integrity: sha512-nBeQgg/ZZA3u3SYxyaDvpvDtgZ/EZPF547ARgZBrG9Bhu1vKDwAIjtIf+sDtJUKa2zOcEbmRLBRSyMraS/Oy1A==, - } + resolution: {integrity: sha512-nBeQgg/ZZA3u3SYxyaDvpvDtgZ/EZPF547ARgZBrG9Bhu1vKDwAIjtIf+sDtJUKa2zOcEbmRLBRSyMraS/Oy1A==} ajv@8.17.1: - resolution: - { - integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==, - } + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} ansi-colors@4.1.3: - resolution: - { - integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} ansi-escapes@4.3.2: - resolution: - { - integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} ansi-regex@5.0.1: - resolution: - { - integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} ansi-regex@6.2.2: - resolution: - { - integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==, - } - engines: { node: '>=12' } + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} ansi-styles@3.2.1: - resolution: - { - integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} ansi-styles@4.3.0: - resolution: - { - integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} ansi-styles@5.2.0: - resolution: - { - integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} ansi-styles@6.2.3: - resolution: - { - integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==, - } - engines: { node: '>=12' } + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} anymatch@3.1.3: - resolution: - { - integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==, - } - engines: { node: '>= 8' } + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} appstash@0.3.0: - resolution: - { - integrity: sha512-F4rMrok4wQYDVitYMWbPQh2MBoKCj7GYzmI/Gw8zDeO2vDLmCmyzmbd0zAwplghB6X3VMGQw/NKcngIc8w6oTA==, - } + resolution: {integrity: sha512-F4rMrok4wQYDVitYMWbPQh2MBoKCj7GYzmI/Gw8zDeO2vDLmCmyzmbd0zAwplghB6X3VMGQw/NKcngIc8w6oTA==} aproba@2.0.0: - resolution: - { - integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==, - } + resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} arg@4.1.3: - resolution: - { - integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==, - } + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} argparse@1.0.10: - resolution: - { - integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==, - } + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} argparse@2.0.1: - resolution: - { - integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, - } + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} aria-query@4.2.2: - resolution: - { - integrity: sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==, - } - engines: { node: '>=6.0' } + resolution: {integrity: sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==} + engines: {node: '>=6.0'} array-differ@3.0.0: - resolution: - { - integrity: sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==} + engines: {node: '>=8'} array-ify@1.0.0: - resolution: - { - integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==, - } + resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} array-union@2.1.0: - resolution: - { - integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} arrify@1.0.1: - resolution: - { - integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} + engines: {node: '>=0.10.0'} arrify@2.0.1: - resolution: - { - integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} + engines: {node: '>=8'} asap@2.0.6: - resolution: - { - integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==, - } + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} asn1@0.2.6: - resolution: - { - integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==, - } + resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} assert-plus@1.0.0: - resolution: - { - integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==, - } - engines: { node: '>=0.8' } + resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} + engines: {node: '>=0.8'} async-retry@1.3.1: - resolution: - { - integrity: sha512-aiieFW/7h3hY0Bq5d+ktDBejxuwR78vRu9hDUdR8rNhSaQ29VzPL4AoIRG7D/c7tdenwOcKvgPM6tIxB3cB6HA==, - } + resolution: {integrity: sha512-aiieFW/7h3hY0Bq5d+ktDBejxuwR78vRu9hDUdR8rNhSaQ29VzPL4AoIRG7D/c7tdenwOcKvgPM6tIxB3cB6HA==} async@3.2.6: - resolution: - { - integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==, - } + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} asynckit@0.4.0: - resolution: - { - integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==, - } + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} atob@2.1.2: - resolution: - { - integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==, - } - engines: { node: '>= 4.5.0' } + resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} + engines: {node: '>= 4.5.0'} hasBin: true aws-sign2@0.7.0: - resolution: - { - integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==, - } + resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} aws4@1.13.2: - resolution: - { - integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==, - } + resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} axios@1.13.2: - resolution: - { - integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==, - } + resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} babel-jest@30.2.0: - resolution: - { - integrity: sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: '@babel/core': ^7.11.0 || ^8.0.0-0 babel-plugin-istanbul@7.0.1: - resolution: - { - integrity: sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==, - } - engines: { node: '>=12' } + resolution: {integrity: sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==} + engines: {node: '>=12'} babel-plugin-jest-hoist@30.2.0: - resolution: - { - integrity: sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} babel-plugin-styled-components@2.1.4: - resolution: - { - integrity: sha512-Xgp9g+A/cG47sUyRwwYxGM4bR/jDRg5N6it/8+HxCnbT5XNKSKDT9xm4oag/osgqjC2It/vH0yXsomOG6k558g==, - } + resolution: {integrity: sha512-Xgp9g+A/cG47sUyRwwYxGM4bR/jDRg5N6it/8+HxCnbT5XNKSKDT9xm4oag/osgqjC2It/vH0yXsomOG6k558g==} peerDependencies: styled-components: '>= 2' babel-preset-current-node-syntax@1.2.0: - resolution: - { - integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==, - } + resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==} peerDependencies: '@babel/core': ^7.0.0 || ^8.0.0-0 babel-preset-jest@30.2.0: - resolution: - { - integrity: sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: '@babel/core': ^7.11.0 || ^8.0.0-beta.1 babel-runtime@6.25.0: - resolution: - { - integrity: sha512-zeCYxDePWYAT/DfmQWIHsMSFW2vv45UIwIAMjGvQVsTd47RwsiRH0uK1yzyWZ7LDBKdhnGDPM6NYEO5CZyhPrg==, - } + resolution: {integrity: sha512-zeCYxDePWYAT/DfmQWIHsMSFW2vv45UIwIAMjGvQVsTd47RwsiRH0uK1yzyWZ7LDBKdhnGDPM6NYEO5CZyhPrg==} backo2@1.0.2: - resolution: - { - integrity: sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==, - } + resolution: {integrity: sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==} balanced-match@1.0.2: - resolution: - { - integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, - } + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} base-64@1.0.0: - resolution: - { - integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==, - } + resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==} base32.js@0.1.0: - resolution: - { - integrity: sha512-n3TkB02ixgBOhTvANakDb4xaMXnYUVkNoRFJjQflcqMQhyEKxEHdj3E6N8t8sUQ0mjH/3/JxzlXuz3ul/J90pQ==, - } - engines: { node: '>=0.12.0' } + resolution: {integrity: sha512-n3TkB02ixgBOhTvANakDb4xaMXnYUVkNoRFJjQflcqMQhyEKxEHdj3E6N8t8sUQ0mjH/3/JxzlXuz3ul/J90pQ==} + engines: {node: '>=0.12.0'} base64-js@1.5.1: - resolution: - { - integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==, - } + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} baseline-browser-mapping@2.9.15: - resolution: - { - integrity: sha512-kX8h7K2srmDyYnXRIppo4AH/wYgzWVCs+eKr3RusRSQ5PvRYoEFmR/I0PbdTjKFAoKqp5+kbxnNTFO9jOfSVJg==, - } + resolution: {integrity: sha512-kX8h7K2srmDyYnXRIppo4AH/wYgzWVCs+eKr3RusRSQ5PvRYoEFmR/I0PbdTjKFAoKqp5+kbxnNTFO9jOfSVJg==} hasBin: true bcrypt-pbkdf@1.0.2: - resolution: - { - integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==, - } + resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} before-after-hook@2.2.3: - resolution: - { - integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==, - } + resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} big-integer@1.6.52: - resolution: - { - integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==, - } - engines: { node: '>=0.6' } + resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} + engines: {node: '>=0.6'} bin-links@4.0.4: - resolution: - { - integrity: sha512-cMtq4W5ZsEwcutJrVId+a/tjt8GSbS+h0oNkdl6+6rBuEv8Ot33Bevj5KPm40t309zuhVic8NjpuL42QCiJWWA==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-cMtq4W5ZsEwcutJrVId+a/tjt8GSbS+h0oNkdl6+6rBuEv8Ot33Bevj5KPm40t309zuhVic8NjpuL42QCiJWWA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} binary-extensions@2.3.0: - resolution: - { - integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} bl@4.1.0: - resolution: - { - integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==, - } + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} body-parser@1.19.0: - resolution: - { - integrity: sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==, - } - engines: { node: '>= 0.8' } + resolution: {integrity: sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==} + engines: {node: '>= 0.8'} body-parser@2.2.1: - resolution: - { - integrity: sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==} + engines: {node: '>=18'} boolbase@1.0.0: - resolution: - { - integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==, - } + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} bowser@2.13.1: - resolution: - { - integrity: sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw==, - } + resolution: {integrity: sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw==} brace-expansion@1.1.12: - resolution: - { - integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==, - } + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} brace-expansion@2.0.2: - resolution: - { - integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==, - } + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} braces@3.0.3: - resolution: - { - integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} broadcast-channel@3.7.0: - resolution: - { - integrity: sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==, - } + resolution: {integrity: sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==} browserslist@4.28.1: - resolution: - { - integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==, - } - engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true bs-logger@0.2.6: - resolution: - { - integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==, - } - engines: { node: '>= 6' } + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} bser@2.1.1: - resolution: - { - integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==, - } + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} buffer-equal-constant-time@1.0.1: - resolution: - { - integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==, - } + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} buffer-from@1.1.2: - resolution: - { - integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==, - } + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} buffer@5.6.0: - resolution: - { - integrity: sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==, - } + resolution: {integrity: sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==} buffer@5.7.1: - resolution: - { - integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==, - } + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} busboy@0.3.1: - resolution: - { - integrity: sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==, - } - engines: { node: '>=4.5.0' } + resolution: {integrity: sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==} + engines: {node: '>=4.5.0'} byte-size@8.1.1: - resolution: - { - integrity: sha512-tUkzZWK0M/qdoLEqikxBWe4kumyuwjl3HO6zHTr4yEI23EojPtLYXdG1+AQY7MN0cGyNDvEaJ8wiYQm6P2bPxg==, - } - engines: { node: '>=12.17' } + resolution: {integrity: sha512-tUkzZWK0M/qdoLEqikxBWe4kumyuwjl3HO6zHTr4yEI23EojPtLYXdG1+AQY7MN0cGyNDvEaJ8wiYQm6P2bPxg==} + engines: {node: '>=12.17'} bytes@3.1.0: - resolution: - { - integrity: sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==, - } - engines: { node: '>= 0.8' } + resolution: {integrity: sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==} + engines: {node: '>= 0.8'} bytes@3.1.2: - resolution: - { - integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==, - } - engines: { node: '>= 0.8' } + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} cacache@18.0.4: - resolution: - { - integrity: sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==} + engines: {node: ^16.14.0 || >=18.0.0} call-bind-apply-helpers@1.0.2: - resolution: - { - integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} call-bind@1.0.8: - resolution: - { - integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} call-bound@1.0.4: - resolution: - { - integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==, - } - engines: { node: '>= 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' } + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} camel-case@3.0.0: - resolution: - { - integrity: sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==, - } + resolution: {integrity: sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==} camelcase-keys@6.2.2: - resolution: - { - integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} + engines: {node: '>=8'} camelcase@5.3.1: - resolution: - { - integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} camelcase@6.3.0: - resolution: - { - integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} camelize@1.0.1: - resolution: - { - integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==, - } + resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} caniuse-lite@1.0.30001765: - resolution: - { - integrity: sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ==, - } + resolution: {integrity: sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ==} case@1.6.3: - resolution: - { - integrity: sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==, - } - engines: { node: '>= 0.8.0' } + resolution: {integrity: sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==} + engines: {node: '>= 0.8.0'} caseless@0.12.0: - resolution: - { - integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==, - } + resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} chalk@2.4.2: - resolution: - { - integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} chalk@3.0.0: - resolution: - { - integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} + engines: {node: '>=8'} chalk@4.1.0: - resolution: - { - integrity: sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==} + engines: {node: '>=10'} chalk@4.1.2: - resolution: - { - integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} char-regex@1.0.2: - resolution: - { - integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} chardet@2.1.1: - resolution: - { - integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==, - } + resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} cheerio-select@2.1.0: - resolution: - { - integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==, - } + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} cheerio@1.0.0-rc.3: - resolution: - { - integrity: sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==, - } - engines: { node: '>= 0.6' } + resolution: {integrity: sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==} + engines: {node: '>= 0.6'} cheerio@1.1.2: - resolution: - { - integrity: sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==, - } - engines: { node: '>=20.18.1' } + resolution: {integrity: sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==} + engines: {node: '>=20.18.1'} chokidar@3.6.0: - resolution: - { - integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==, - } - engines: { node: '>= 8.10.0' } + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} chownr@2.0.0: - resolution: - { - integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} ci-info@3.9.0: - resolution: - { - integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} ci-info@4.3.1: - resolution: - { - integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + engines: {node: '>=8'} cjs-module-lexer@2.2.0: - resolution: - { - integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==, - } + resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} clean-ansi@0.2.0: - resolution: - { - integrity: sha512-AX26I7oo87AIA4OixLOARtjeNdX85aKGI+HPJ7wQEnXkoC3ytbwIuPu3d5+cmDoh2j1I2pQsQa/z3/FNAR8vOQ==, - } + resolution: {integrity: sha512-AX26I7oo87AIA4OixLOARtjeNdX85aKGI+HPJ7wQEnXkoC3ytbwIuPu3d5+cmDoh2j1I2pQsQa/z3/FNAR8vOQ==} clean-css@4.2.4: - resolution: - { - integrity: sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==, - } - engines: { node: '>= 4.0' } + resolution: {integrity: sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==} + engines: {node: '>= 4.0'} clean-stack@2.2.0: - resolution: - { - integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} cli-cursor@3.1.0: - resolution: - { - integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} cli-spinners@2.6.1: - resolution: - { - integrity: sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==} + engines: {node: '>=6'} cli-spinners@2.9.2: - resolution: - { - integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} cli-width@3.0.0: - resolution: - { - integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==, - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} + engines: {node: '>= 10'} cliui@6.0.0: - resolution: - { - integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==, - } + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} cliui@7.0.4: - resolution: - { - integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==, - } + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} cliui@8.0.1: - resolution: - { - integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==, - } - engines: { node: '>=12' } + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} clone-deep@4.0.1: - resolution: - { - integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} + engines: {node: '>=6'} clone@1.0.4: - resolution: - { - integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==, - } - engines: { node: '>=0.8' } + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} cmd-shim@6.0.3: - resolution: - { - integrity: sha512-FMabTRlc5t5zjdenF6mS0MBeFZm0XqHqeOkcskKFb/LYCcRQ5fVgLOHVc4Lq9CqABd9zhjwPjMBCJvMCziSVtA==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-FMabTRlc5t5zjdenF6mS0MBeFZm0XqHqeOkcskKFb/LYCcRQ5fVgLOHVc4Lq9CqABd9zhjwPjMBCJvMCziSVtA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} co@4.6.0: - resolution: - { - integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==, - } - engines: { iojs: '>= 1.0.0', node: '>= 0.12.0' } + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} collect-v8-coverage@1.0.3: - resolution: - { - integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==, - } + resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==} color-convert@1.9.3: - resolution: - { - integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==, - } + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} color-convert@2.0.1: - resolution: - { - integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, - } - engines: { node: '>=7.0.0' } + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} color-name@1.1.3: - resolution: - { - integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==, - } + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} color-name@1.1.4: - resolution: - { - integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, - } + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} color-support@1.1.3: - resolution: - { - integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==, - } + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} hasBin: true columnify@1.6.0: - resolution: - { - integrity: sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==, - } - engines: { node: '>=8.0.0' } + resolution: {integrity: sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==} + engines: {node: '>=8.0.0'} combined-stream@1.0.8: - resolution: - { - integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, - } - engines: { node: '>= 0.8' } + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} commander@10.0.1: - resolution: - { - integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} commander@2.17.1: - resolution: - { - integrity: sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==, - } + resolution: {integrity: sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==} commander@2.19.0: - resolution: - { - integrity: sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==, - } + resolution: {integrity: sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==} commander@2.20.3: - resolution: - { - integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==, - } + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} commander@5.1.0: - resolution: - { - integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==, - } - engines: { node: '>= 6' } + resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} + engines: {node: '>= 6'} common-ancestor-path@1.0.1: - resolution: - { - integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==, - } + resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} compare-func@2.0.0: - resolution: - { - integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==, - } + resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} component-emitter@1.3.1: - resolution: - { - integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==, - } + resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} concat-map@0.0.1: - resolution: - { - integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, - } + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} concat-stream@2.0.0: - resolution: - { - integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==, - } - engines: { '0': node >= 6.0 } + resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} + engines: {'0': node >= 6.0} config-chain@1.1.13: - resolution: - { - integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==, - } + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} console-control-strings@1.1.0: - resolution: - { - integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==, - } + resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} content-disposition@1.0.1: - resolution: - { - integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} + engines: {node: '>=18'} content-type@1.0.5: - resolution: - { - integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==, - } - engines: { node: '>= 0.6' } + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} conventional-changelog-angular@7.0.0: - resolution: - { - integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==, - } - engines: { node: '>=16' } + resolution: {integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==} + engines: {node: '>=16'} conventional-changelog-core@5.0.1: - resolution: - { - integrity: sha512-Rvi5pH+LvgsqGwZPZ3Cq/tz4ty7mjijhr3qR4m9IBXNbxGGYgTVVO+duXzz9aArmHxFtwZ+LRkrNIMDQzgoY4A==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-Rvi5pH+LvgsqGwZPZ3Cq/tz4ty7mjijhr3qR4m9IBXNbxGGYgTVVO+duXzz9aArmHxFtwZ+LRkrNIMDQzgoY4A==} + engines: {node: '>=14'} conventional-changelog-preset-loader@3.0.0: - resolution: - { - integrity: sha512-qy9XbdSLmVnwnvzEisjxdDiLA4OmV3o8db+Zdg4WiFw14fP3B6XNz98X0swPPpkTd/pc1K7+adKgEDM1JCUMiA==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-qy9XbdSLmVnwnvzEisjxdDiLA4OmV3o8db+Zdg4WiFw14fP3B6XNz98X0swPPpkTd/pc1K7+adKgEDM1JCUMiA==} + engines: {node: '>=14'} conventional-changelog-writer@6.0.1: - resolution: - { - integrity: sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ==} + engines: {node: '>=14'} hasBin: true conventional-commits-filter@3.0.0: - resolution: - { - integrity: sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q==} + engines: {node: '>=14'} conventional-commits-parser@4.0.0: - resolution: - { - integrity: sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==} + engines: {node: '>=14'} hasBin: true conventional-recommended-bump@7.0.1: - resolution: - { - integrity: sha512-Ft79FF4SlOFvX4PkwFDRnaNiIVX7YbmqGU0RwccUaiGvgp3S0a8ipR2/Qxk31vclDNM+GSdJOVs2KrsUCjblVA==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-Ft79FF4SlOFvX4PkwFDRnaNiIVX7YbmqGU0RwccUaiGvgp3S0a8ipR2/Qxk31vclDNM+GSdJOVs2KrsUCjblVA==} + engines: {node: '>=14'} hasBin: true convert-source-map@2.0.0: - resolution: - { - integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==, - } + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} cookie-signature@1.2.2: - resolution: - { - integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==, - } - engines: { node: '>=6.6.0' } + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} cookie@0.7.2: - resolution: - { - integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==, - } - engines: { node: '>= 0.6' } + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} cookiejar@2.1.4: - resolution: - { - integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==, - } + resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} copyfiles@2.4.1: - resolution: - { - integrity: sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==, - } + resolution: {integrity: sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==} hasBin: true core-js-pure@3.47.0: - resolution: - { - integrity: sha512-BcxeDbzUrRnXGYIVAGFtcGQVNpFcUhVjr6W7F8XktvQW2iJP9e66GP6xdKotCRFlrxBvNIBrhwKteRXqMV86Nw==, - } + resolution: {integrity: sha512-BcxeDbzUrRnXGYIVAGFtcGQVNpFcUhVjr6W7F8XktvQW2iJP9e66GP6xdKotCRFlrxBvNIBrhwKteRXqMV86Nw==} core-js@2.6.12: - resolution: - { - integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==, - } + resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==} deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js. core-util-is@1.0.2: - resolution: - { - integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==, - } + resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} core-util-is@1.0.3: - resolution: - { - integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==, - } + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} cors@2.8.5: - resolution: - { - integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==, - } - engines: { node: '>= 0.10' } + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} cosmiconfig@9.0.0: - resolution: - { - integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} peerDependencies: typescript: '>=4.9.5' peerDependenciesMeta: @@ -6962,134 +5444,74 @@ packages: optional: true create-require@1.1.1: - resolution: - { - integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==, - } + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} cron-parser@2.18.0: - resolution: - { - integrity: sha512-s4odpheTyydAbTBQepsqd2rNWGa2iV3cyo8g7zbI2QQYGLVsfbhmwukayS1XHppe02Oy1fg7mg6xoaraVJeEcg==, - } - engines: { node: '>=0.8' } + resolution: {integrity: sha512-s4odpheTyydAbTBQepsqd2rNWGa2iV3cyo8g7zbI2QQYGLVsfbhmwukayS1XHppe02Oy1fg7mg6xoaraVJeEcg==} + engines: {node: '>=0.8'} cross-spawn@7.0.6: - resolution: - { - integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==, - } - engines: { node: '>= 8' } + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} css-color-keywords@1.0.0: - resolution: - { - integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==} + engines: {node: '>=4'} css-select@1.2.0: - resolution: - { - integrity: sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA==, - } + resolution: {integrity: sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA==} css-select@5.2.2: - resolution: - { - integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==, - } + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} css-to-react-native@3.2.0: - resolution: - { - integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==, - } + resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==} css-what@2.1.3: - resolution: - { - integrity: sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==, - } + resolution: {integrity: sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==} css-what@6.2.2: - resolution: - { - integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==, - } - engines: { node: '>= 6' } + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} css.escape@1.5.1: - resolution: - { - integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==, - } + resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} css@3.0.0: - resolution: - { - integrity: sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==, - } + resolution: {integrity: sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==} cssesc@3.0.0: - resolution: - { - integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} hasBin: true csstype@3.2.3: - resolution: - { - integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==, - } + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} csv-parse@6.1.0: - resolution: - { - integrity: sha512-CEE+jwpgLn+MmtCpVcPtiCZpVtB6Z2OKPTr34pycYYoL7sxdOkXDdQ4lRiw6ioC0q6BLqhc6cKweCVvral8yhw==, - } + resolution: {integrity: sha512-CEE+jwpgLn+MmtCpVcPtiCZpVtB6Z2OKPTr34pycYYoL7sxdOkXDdQ4lRiw6ioC0q6BLqhc6cKweCVvral8yhw==} csv-parser@2.3.5: - resolution: - { - integrity: sha512-LCHolC4AlNwL+5EuD5LH2VVNKpD8QixZW2zzK1XmrVYUaslFY4c5BooERHOCIubG9iv/DAyFjs4x0HvWNZuyWg==, - } - engines: { node: '>= 8.16.0' } + resolution: {integrity: sha512-LCHolC4AlNwL+5EuD5LH2VVNKpD8QixZW2zzK1XmrVYUaslFY4c5BooERHOCIubG9iv/DAyFjs4x0HvWNZuyWg==} + engines: {node: '>= 8.16.0'} hasBin: true dargs@7.0.0: - resolution: - { - integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==} + engines: {node: '>=8'} dashdash@1.14.1: - resolution: - { - integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==, - } - engines: { node: '>=0.10' } + resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} + engines: {node: '>=0.10'} dataloader@2.2.3: - resolution: - { - integrity: sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==, - } + resolution: {integrity: sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==} dateformat@3.0.3: - resolution: - { - integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==, - } + resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==} debug@2.6.9: - resolution: - { - integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==, - } + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: supports-color: '*' peerDependenciesMeta: @@ -7097,11 +5519,8 @@ packages: optional: true debug@4.4.3: - resolution: - { - integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==, - } - engines: { node: '>=6.0' } + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} peerDependencies: supports-color: '*' peerDependenciesMeta: @@ -7109,31 +5528,19 @@ packages: optional: true decamelize-keys@1.1.1: - resolution: - { - integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} + engines: {node: '>=0.10.0'} decamelize@1.2.0: - resolution: - { - integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} decode-uri-component@0.2.2: - resolution: - { - integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==, - } - engines: { node: '>=0.10' } + resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} + engines: {node: '>=0.10'} dedent@1.5.3: - resolution: - { - integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==, - } + resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} peerDependencies: babel-plugin-macros: ^3.1.0 peerDependenciesMeta: @@ -7141,10 +5548,7 @@ packages: optional: true dedent@1.7.1: - resolution: - { - integrity: sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==, - } + resolution: {integrity: sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==} peerDependencies: babel-plugin-macros: ^3.1.0 peerDependenciesMeta: @@ -7152,238 +5556,130 @@ packages: optional: true deep-is@0.1.4: - resolution: - { - integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, - } + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} deepmerge@4.3.1: - resolution: - { - integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==, - } - engines: { node: '>=0.10.0' } + 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==, - } + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} define-data-property@1.1.4: - resolution: - { - integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} define-lazy-prop@2.0.0: - resolution: - { - integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} define-properties@1.2.1: - resolution: - { - integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} delayed-stream@1.0.0: - resolution: - { - integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==, - } - engines: { node: '>=0.4.0' } + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} depd@1.1.2: - resolution: - { - integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==, - } - engines: { node: '>= 0.6' } + resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} + engines: {node: '>= 0.6'} depd@2.0.0: - resolution: - { - integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==, - } - engines: { node: '>= 0.8' } + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} deprecation@2.3.1: - resolution: - { - integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==, - } + resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} detect-indent@5.0.0: - resolution: - { - integrity: sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==} + engines: {node: '>=4'} detect-newline@3.1.0: - resolution: - { - integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} detect-node@2.1.0: - resolution: - { - integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==, - } + resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} dezalgo@1.0.4: - resolution: - { - integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==, - } + resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} dicer@0.3.0: - resolution: - { - integrity: sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==, - } - engines: { node: '>=4.5.0' } + resolution: {integrity: sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==} + engines: {node: '>=4.5.0'} diff-sequences@29.6.3: - resolution: - { - integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==, - } - engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} diff@4.0.2: - resolution: - { - integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==, - } - engines: { node: '>=0.3.1' } + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} dom-accessibility-api@0.5.16: - resolution: - { - integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==, - } + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} dom-serializer@0.1.1: - resolution: - { - integrity: sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==, - } + resolution: {integrity: sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==} dom-serializer@0.2.2: - resolution: - { - integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==, - } + resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==} dom-serializer@1.4.1: - resolution: - { - integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==, - } + resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} dom-serializer@2.0.0: - resolution: - { - integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==, - } + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} domelementtype@1.3.1: - resolution: - { - integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==, - } + resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==} domelementtype@2.3.0: - resolution: - { - integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==, - } + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} domhandler@2.4.2: - resolution: - { - integrity: sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==, - } + resolution: {integrity: sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==} domhandler@3.3.0: - resolution: - { - integrity: sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==, - } - engines: { node: '>= 4' } + resolution: {integrity: sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==} + engines: {node: '>= 4'} domhandler@4.3.1: - resolution: - { - integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==, - } - engines: { node: '>= 4' } + resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} + engines: {node: '>= 4'} domhandler@5.0.3: - resolution: - { - integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==, - } - engines: { node: '>= 4' } + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} domutils@1.5.1: - resolution: - { - integrity: sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==, - } + resolution: {integrity: sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==} domutils@1.7.0: - resolution: - { - integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==, - } + resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==} domutils@2.8.0: - resolution: - { - integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==, - } + resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} domutils@3.2.2: - resolution: - { - integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==, - } + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} dot-prop@5.3.0: - resolution: - { - integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} + engines: {node: '>=8'} dotenv-expand@11.0.7: - resolution: - { - integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==, - } - engines: { node: '>=12' } + resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} + engines: {node: '>=12'} dotenv@16.4.7: - resolution: - { - integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==, - } - engines: { node: '>=12' } + resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} + engines: {node: '>=12'} drizzle-orm@0.45.1: - resolution: - { - integrity: sha512-Te0FOdKIistGNPMq2jscdqngBRfBpC8uMFVwqjf6gtTVJHIQ/dosgV/CLBU2N4ZJBsXL5savCba9b0YJskKdcA==, - } + resolution: {integrity: sha512-Te0FOdKIistGNPMq2jscdqngBRfBpC8uMFVwqjf6gtTVJHIQ/dosgV/CLBU2N4ZJBsXL5savCba9b0YJskKdcA==} peerDependencies: '@aws-sdk/client-rds-data': '>=3' '@cloudflare/workers-types': '>=4' @@ -7475,268 +5771,156 @@ packages: optional: true dunder-proto@1.0.1: - resolution: - { - integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} eastasianwidth@0.2.0: - resolution: - { - integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==, - } + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} ecc-jsbn@0.1.2: - resolution: - { - integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==, - } + resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} ecdsa-sig-formatter@1.0.11: - resolution: - { - integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==, - } + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} editorconfig@1.0.4: - resolution: - { - integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==} + engines: {node: '>=14'} hasBin: true ee-first@1.1.1: - resolution: - { - integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==, - } + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} ejs@3.1.10: - resolution: - { - integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} hasBin: true electron-to-chromium@1.5.267: - resolution: - { - integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==, - } + resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} emittery@0.13.1: - resolution: - { - integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==, - } - engines: { node: '>=12' } + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} emoji-regex@8.0.0: - resolution: - { - integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, - } + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} emoji-regex@9.2.2: - resolution: - { - integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, - } + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} encodeurl@2.0.0: - resolution: - { - integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==, - } - engines: { node: '>= 0.8' } + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} encoding-sniffer@0.2.1: - resolution: - { - integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==, - } + resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} encoding@0.1.13: - resolution: - { - integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==, - } + resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} end-of-stream@1.4.5: - resolution: - { - integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==, - } + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} enquirer@2.3.6: - resolution: - { - integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==, - } - engines: { node: '>=8.6' } + resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} + engines: {node: '>=8.6'} entities@1.1.2: - resolution: - { - integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==, - } + resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==} entities@2.2.0: - resolution: - { - integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==, - } + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} entities@4.5.0: - resolution: - { - integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==, - } - engines: { node: '>=0.12' } + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} entities@6.0.1: - resolution: - { - integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==, - } - engines: { node: '>=0.12' } + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} env-paths@2.2.1: - resolution: - { - integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} envalid@8.1.1: - resolution: - { - integrity: sha512-vOUfHxAFFvkBjbVQbBfgnCO9d3GcNfMMTtVfgqSU2rQGMFEVqWy9GBuoSfHnwGu7EqR0/GeukQcL3KjFBaga9w==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-vOUfHxAFFvkBjbVQbBfgnCO9d3GcNfMMTtVfgqSU2rQGMFEVqWy9GBuoSfHnwGu7EqR0/GeukQcL3KjFBaga9w==} + engines: {node: '>=18'} envinfo@7.13.0: - resolution: - { - integrity: sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==} + engines: {node: '>=4'} hasBin: true err-code@2.0.3: - resolution: - { - integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==, - } + resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} error-ex@1.3.4: - resolution: - { - integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==, - } + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} es-define-property@1.0.1: - resolution: - { - integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} es-errors@1.3.0: - resolution: - { - integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} es-object-atoms@1.1.1: - resolution: - { - integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} es-set-tostringtag@2.1.0: - resolution: - { - integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true esbuild@0.27.2: - resolution: - { - integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} + engines: {node: '>=18'} hasBin: true escalade@3.2.0: - resolution: - { - integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} escape-goat@3.0.0: - resolution: - { - integrity: sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==} + engines: {node: '>=10'} escape-html@1.0.3: - resolution: - { - integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==, - } + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} escape-string-regexp@1.0.5: - resolution: - { - integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==, - } - engines: { node: '>=0.8.0' } + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} escape-string-regexp@2.0.0: - resolution: - { - integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} escape-string-regexp@4.0.0: - resolution: - { - integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} eslint-config-prettier@10.1.8: - resolution: - { - integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==, - } + resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} hasBin: true peerDependencies: eslint: '>=7.0.0' eslint-plugin-simple-import-sort@12.1.1: - resolution: - { - integrity: sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==, - } + resolution: {integrity: sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==} peerDependencies: eslint: '>=5.0.0' eslint-plugin-unused-imports@4.3.0: - resolution: - { - integrity: sha512-ZFBmXMGBYfHttdRtOG9nFFpmUvMtbHSjsKrS20vdWdbfiVYsO3yA2SGYy9i9XmZJDfMGBflZGBCm70SEnFQtOA==, - } + resolution: {integrity: sha512-ZFBmXMGBYfHttdRtOG9nFFpmUvMtbHSjsKrS20vdWdbfiVYsO3yA2SGYy9i9XmZJDfMGBflZGBCm70SEnFQtOA==} peerDependencies: '@typescript-eslint/eslint-plugin': ^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0 eslint: ^9.0.0 || ^8.0.0 @@ -7745,32 +5929,20 @@ packages: optional: true eslint-scope@8.4.0: - resolution: - { - integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} eslint-visitor-keys@3.4.3: - resolution: - { - integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==, - } - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} eslint-visitor-keys@4.2.1: - resolution: - { - integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} eslint@9.39.2: - resolution: - { - integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: jiti: '*' @@ -7779,190 +5951,106 @@ packages: optional: true espree@10.4.0: - resolution: - { - integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} esprima@4.0.1: - resolution: - { - integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} hasBin: true esquery@1.6.0: - resolution: - { - integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==, - } - engines: { node: '>=0.10' } + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} esrecurse@4.3.0: - resolution: - { - integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==, - } - engines: { node: '>=4.0' } + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} estraverse@5.3.0: - resolution: - { - integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==, - } - engines: { node: '>=4.0' } + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} esutils@2.0.3: - resolution: - { - integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} etag@1.8.1: - resolution: - { - integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==, - } - engines: { node: '>= 0.6' } + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} eventemitter3@3.1.2: - resolution: - { - integrity: sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==, - } + resolution: {integrity: sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==} eventemitter3@4.0.7: - resolution: - { - integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==, - } + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} events@3.3.0: - resolution: - { - integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==, - } - engines: { node: '>=0.8.x' } + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} execa@5.0.0: - resolution: - { - integrity: sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==} + engines: {node: '>=10'} execa@5.1.1: - resolution: - { - integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} exit-x@0.2.2: - resolution: - { - integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==, - } - engines: { node: '>= 0.8.0' } + resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==} + engines: {node: '>= 0.8.0'} expect@30.2.0: - resolution: - { - integrity: sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} exponential-backoff@3.1.3: - resolution: - { - integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==, - } + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} express@5.2.1: - resolution: - { - integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==, - } - engines: { node: '>= 18' } + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} extend@3.0.2: - resolution: - { - integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==, - } + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} extsprintf@1.3.0: - resolution: - { - integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==, - } - engines: { '0': node >=0.6.0 } + resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} + engines: {'0': node >=0.6.0} fast-deep-equal@3.1.3: - resolution: - { - integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, - } + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} fast-glob@3.3.3: - resolution: - { - integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==, - } - engines: { node: '>=8.6.0' } + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} fast-json-stable-stringify@2.1.0: - resolution: - { - integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==, - } + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} fast-levenshtein@2.0.6: - resolution: - { - integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, - } + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} fast-safe-stringify@2.1.1: - resolution: - { - integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==, - } + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} fast-uri@3.1.0: - resolution: - { - integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==, - } + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} fast-xml-parser@5.2.5: - resolution: - { - integrity: sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==, - } + resolution: {integrity: sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==} hasBin: true fastq@1.20.1: - resolution: - { - integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==, - } + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} fb-watchman@2.0.2: - resolution: - { - integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==, - } + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} fdir@6.5.0: - resolution: - { - integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==, - } - engines: { node: '>=12.0.0' } + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: @@ -7970,99 +6058,57 @@ packages: optional: true figures@3.2.0: - resolution: - { - integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} + engines: {node: '>=8'} file-entry-cache@8.0.0: - resolution: - { - integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==, - } - engines: { node: '>=16.0.0' } + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} filelist@1.0.4: - resolution: - { - integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==, - } + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} fill-range@7.1.1: - resolution: - { - integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} finalhandler@1.3.2: - resolution: - { - integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==, - } - engines: { node: '>= 0.8' } + resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} + engines: {node: '>= 0.8'} finalhandler@2.1.1: - resolution: - { - integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==, - } - engines: { node: '>= 18.0.0' } + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} find-and-require-package-json@0.9.0: - resolution: - { - integrity: sha512-e7+fnRvphmWHHgOdVQct5yLEmw38GD3wpX8CMONT/qn/BLK6F0ft/iPicNKJMX6U4GlTEFzreYbLf+FlCYh4lQ==, - } + resolution: {integrity: sha512-e7+fnRvphmWHHgOdVQct5yLEmw38GD3wpX8CMONT/qn/BLK6F0ft/iPicNKJMX6U4GlTEFzreYbLf+FlCYh4lQ==} find-up@2.1.0: - resolution: - { - integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} + engines: {node: '>=4'} find-up@4.1.0: - resolution: - { - integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} find-up@5.0.0: - resolution: - { - integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} flat-cache@4.0.1: - resolution: - { - integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==, - } - engines: { node: '>=16' } + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} flat@5.0.2: - resolution: - { - integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==, - } + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} hasBin: true flatted@3.3.3: - resolution: - { - integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==, - } + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} follow-redirects@1.15.11: - resolution: - { - integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==, - } - engines: { node: '>=4.0' } + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + engines: {node: '>=4.0'} peerDependencies: debug: '*' peerDependenciesMeta: @@ -8070,1069 +6116,610 @@ packages: optional: true foreground-child@3.3.1: - resolution: - { - integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} forever-agent@0.6.1: - resolution: - { - integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==, - } + resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} form-data@2.3.3: - resolution: - { - integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==, - } - engines: { node: '>= 0.12' } + resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} + engines: {node: '>= 0.12'} form-data@4.0.5: - resolution: - { - integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==, - } - engines: { node: '>= 6' } + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} formidable@3.5.4: - resolution: - { - integrity: sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==, - } - engines: { node: '>=14.0.0' } + resolution: {integrity: sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==} + engines: {node: '>=14.0.0'} forwarded@0.2.0: - resolution: - { - integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==, - } - engines: { node: '>= 0.6' } + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} fresh@2.0.0: - resolution: - { - integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==, - } - engines: { node: '>= 0.8' } + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} front-matter@4.0.2: - resolution: - { - integrity: sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==, - } + resolution: {integrity: sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==} fs-capacitor@6.2.0: - resolution: - { - integrity: sha512-nKcE1UduoSKX27NSZlg879LdQc94OtbOsEmKMN2MBNudXREvijRKx2GEBsTMTfws+BrbkJoEuynbGSVRSpauvw==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-nKcE1UduoSKX27NSZlg879LdQc94OtbOsEmKMN2MBNudXREvijRKx2GEBsTMTfws+BrbkJoEuynbGSVRSpauvw==} + engines: {node: '>=10'} fs-capacitor@8.0.0: - resolution: - { - integrity: sha512-+Lk6iSKajdGw+7XYxUkwIzreJ2G1JFlYOdnKJv5PzwFLVsoJYBpCuS7WPIUSNT1IbQaEWT1nhYU63Ud03DyzLA==, - } - engines: { node: ^14.17.0 || >=16.0.0 } + resolution: {integrity: sha512-+Lk6iSKajdGw+7XYxUkwIzreJ2G1JFlYOdnKJv5PzwFLVsoJYBpCuS7WPIUSNT1IbQaEWT1nhYU63Ud03DyzLA==} + engines: {node: ^14.17.0 || >=16.0.0} fs-constants@1.0.0: - resolution: - { - integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==, - } + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} fs-extra@11.3.3: - resolution: - { - integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==, - } - engines: { node: '>=14.14' } + resolution: {integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==} + engines: {node: '>=14.14'} fs-minipass@2.1.0: - resolution: - { - integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==, - } - engines: { node: '>= 8' } + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} fs-minipass@3.0.3: - resolution: - { - integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} fs.realpath@1.0.0: - resolution: - { - integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==, - } + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} fsevents@2.3.2: - resolution: - { - integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==, - } - engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } + 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 } + 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==, - } + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} genomic@5.3.0: - resolution: - { - integrity: sha512-59rZ++BMgR4/rbh/j55n0BCYAZI/KrP9l7IgxdOHT+HEMAADA6kGaPOhDBltekw2QpHOAUeOXoRiTvntM7b1Ug==, - } + resolution: {integrity: sha512-59rZ++BMgR4/rbh/j55n0BCYAZI/KrP9l7IgxdOHT+HEMAADA6kGaPOhDBltekw2QpHOAUeOXoRiTvntM7b1Ug==} gensync@1.0.0-beta.2: - resolution: - { - integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} get-caller-file@2.0.5: - resolution: - { - integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==, - } - engines: { node: 6.* || 8.* || >= 10.* } + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} get-intrinsic@1.3.0: - resolution: - { - integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} get-package-type@0.1.0: - resolution: - { - integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==, - } - engines: { node: '>=8.0.0' } + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} get-pkg-repo@4.2.1: - resolution: - { - integrity: sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==, - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==} + engines: {node: '>=6.9.0'} hasBin: true get-port@5.1.1: - resolution: - { - integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==} + engines: {node: '>=8'} get-proto@1.0.1: - resolution: - { - integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} get-stream@6.0.0: - resolution: - { - integrity: sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==} + engines: {node: '>=10'} get-stream@6.0.1: - resolution: - { - integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} get-tsconfig@4.13.0: - resolution: - { - integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==, - } + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} getpass@0.1.7: - resolution: - { - integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==, - } + resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} git-raw-commits@3.0.0: - resolution: - { - integrity: sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw==} + engines: {node: '>=14'} hasBin: true git-remote-origin-url@2.0.0: - resolution: - { - integrity: sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==} + engines: {node: '>=4'} git-semver-tags@5.0.1: - resolution: - { - integrity: sha512-hIvOeZwRbQ+7YEUmCkHqo8FOLQZCEn18yevLHADlFPZY02KJGsu5FZt9YW/lybfK2uhWFI7Qg/07LekJiTv7iA==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-hIvOeZwRbQ+7YEUmCkHqo8FOLQZCEn18yevLHADlFPZY02KJGsu5FZt9YW/lybfK2uhWFI7Qg/07LekJiTv7iA==} + engines: {node: '>=14'} hasBin: true git-up@7.0.0: - resolution: - { - integrity: sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==, - } + resolution: {integrity: sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==} git-url-parse@14.0.0: - resolution: - { - integrity: sha512-NnLweV+2A4nCvn4U/m2AoYu0pPKlsmhK9cknG7IMwsjFY1S2jxM+mAhsDxyxfCIGfGaD+dozsyX4b6vkYc83yQ==, - } + resolution: {integrity: sha512-NnLweV+2A4nCvn4U/m2AoYu0pPKlsmhK9cknG7IMwsjFY1S2jxM+mAhsDxyxfCIGfGaD+dozsyX4b6vkYc83yQ==} gitconfiglocal@1.0.0: - resolution: - { - integrity: sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==, - } + resolution: {integrity: sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==} glob-parent@5.1.2: - resolution: - { - integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, - } - engines: { node: '>= 6' } + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} glob-parent@6.0.2: - resolution: - { - integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==, - } - engines: { node: '>=10.13.0' } + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} glob@10.5.0: - resolution: - { - integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==, - } + 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@11.1.0: - resolution: - { - integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==, - } - engines: { node: 20 || >=22 } + resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} + engines: {node: 20 || >=22} + 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.0: - resolution: - { - integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==, - } - engines: { node: 20 || >=22 } + resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==} + engines: {node: 20 || >=22} glob@7.2.3: - resolution: - { - integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==, - } - deprecated: Glob versions prior to v9 are no longer supported + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + 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 glob@9.3.5: - resolution: - { - integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==, - } - engines: { node: '>=16 || 14 >=14.17' } + resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} + engines: {node: '>=16 || 14 >=14.17'} + 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 globals@14.0.0: - resolution: - { - integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} gopd@1.2.0: - resolution: - { - integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==, - } - engines: { node: '>= 0.4' } + 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==, - } + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} graphile-build-pg@4.14.1: - resolution: - { - integrity: sha512-7DIVbcfMU5lXNkGnAeobqm29AvjFYw4/xOlKNQk3NE/mfFDcyPuXYboypmtxzglg1hGXkyONLYnas9vzL+SunQ==, - } - engines: { node: '>=8.6' } + resolution: {integrity: sha512-7DIVbcfMU5lXNkGnAeobqm29AvjFYw4/xOlKNQk3NE/mfFDcyPuXYboypmtxzglg1hGXkyONLYnas9vzL+SunQ==} + engines: {node: '>=8.6'} peerDependencies: pg: '>=6.1.0 <9' graphile-build@4.14.1: - resolution: - { - integrity: sha512-l/ylyMK0vl5LCOScpTsTedNZUqwBgafXS7RPDW1YiQofeioVtTDMdV9k3zRkXdMKtKqJsvOBvjXn64WGLaLInQ==, - } - engines: { node: '>=8.6' } + resolution: {integrity: sha512-l/ylyMK0vl5LCOScpTsTedNZUqwBgafXS7RPDW1YiQofeioVtTDMdV9k3zRkXdMKtKqJsvOBvjXn64WGLaLInQ==} + engines: {node: '>=8.6'} peerDependencies: graphql: '>=0.9 <0.14 || ^14.0.2 || ^15.4.0' graphile-utils@4.14.1: - resolution: - { - integrity: sha512-FgviZVKO3NS8va2inqUVQQFSnFLEG7FiH64BqSVRHSF8jwSXKcpx5NiRibErNvvIdnuzgVAXQ3W4jcXvMSx0Tg==, - } - engines: { node: '>=8.6' } + resolution: {integrity: sha512-FgviZVKO3NS8va2inqUVQQFSnFLEG7FiH64BqSVRHSF8jwSXKcpx5NiRibErNvvIdnuzgVAXQ3W4jcXvMSx0Tg==} + engines: {node: '>=8.6'} peerDependencies: graphile-build: ^4.5.0 graphile-build-pg: ^4.5.0 graphql-parse-resolve-info@4.14.1: - resolution: - { - integrity: sha512-WKHukfEuZamP1ZONR84b8iT+4sJgEhtXMDArm1jpXEsU2vTb5EgkCZ4Obfl+v09oNTKXm0CJjPfBUZ5jcJ2Ykg==, - } - engines: { node: '>=8.6' } + resolution: {integrity: sha512-WKHukfEuZamP1ZONR84b8iT+4sJgEhtXMDArm1jpXEsU2vTb5EgkCZ4Obfl+v09oNTKXm0CJjPfBUZ5jcJ2Ykg==} + engines: {node: '>=8.6'} peerDependencies: graphql: '>=0.9 <0.14 || ^14.0.2 || ^15.4.0 || ^16.3.0' graphql-request@7.4.0: - resolution: - { - integrity: sha512-xfr+zFb/QYbs4l4ty0dltqiXIp07U6sl+tOKAb0t50/EnQek6CVVBLjETXi+FghElytvgaAWtIOt3EV7zLzIAQ==, - } + resolution: {integrity: sha512-xfr+zFb/QYbs4l4ty0dltqiXIp07U6sl+tOKAb0t50/EnQek6CVVBLjETXi+FghElytvgaAWtIOt3EV7zLzIAQ==} peerDependencies: graphql: 14 - 16 graphql-tag@2.12.6: - resolution: - { - integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==} + engines: {node: '>=10'} peerDependencies: graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 graphql-upload@13.0.0: - resolution: - { - integrity: sha512-YKhx8m/uOtKu4Y1UzBFJhbBGJTlk7k4CydlUUiNrtxnwZv0WigbRHP+DVhRNKt7u7DXOtcKZeYJlGtnMXvreXA==, - } - engines: { node: ^12.22.0 || ^14.17.0 || >= 16.0.0 } + resolution: {integrity: sha512-YKhx8m/uOtKu4Y1UzBFJhbBGJTlk7k4CydlUUiNrtxnwZv0WigbRHP+DVhRNKt7u7DXOtcKZeYJlGtnMXvreXA==} + engines: {node: ^12.22.0 || ^14.17.0 || >= 16.0.0} peerDependencies: graphql: 0.13.1 - 16 graphql-ws@5.16.2: - resolution: - { - integrity: sha512-E1uccsZxt/96jH/OwmLPuXMACILs76pKF2i3W861LpKBCYtGIyPQGtWLuBLkND4ox1KHns70e83PS4te50nvPQ==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-E1uccsZxt/96jH/OwmLPuXMACILs76pKF2i3W861LpKBCYtGIyPQGtWLuBLkND4ox1KHns70e83PS4te50nvPQ==} + engines: {node: '>=10'} peerDependencies: graphql: '>=0.11 <=16' graphql@15.10.1: - resolution: - { - integrity: sha512-BL/Xd/T9baO6NFzoMpiMD7YUZ62R6viR5tp/MULVEnbYJXZA//kRNW7J0j1w/wXArgL0sCxhDfK5dczSKn3+cg==, - } - engines: { node: '>= 10.x' } + resolution: {integrity: sha512-BL/Xd/T9baO6NFzoMpiMD7YUZ62R6viR5tp/MULVEnbYJXZA//kRNW7J0j1w/wXArgL0sCxhDfK5dczSKn3+cg==} + engines: {node: '>= 10.x'} handlebars@4.7.8: - resolution: - { - integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==, - } - engines: { node: '>=0.4.7' } + resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} + engines: {node: '>=0.4.7'} hasBin: true har-schema@2.0.0: - resolution: - { - integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} + engines: {node: '>=4'} har-validator@5.1.5: - resolution: - { - integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==} + engines: {node: '>=6'} deprecated: this library is no longer supported hard-rejection@2.1.0: - resolution: - { - integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} + engines: {node: '>=6'} has-flag@3.0.0: - resolution: - { - integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} has-flag@4.0.0: - resolution: - { - integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} has-property-descriptors@1.0.2: - resolution: - { - integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==, - } + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} has-symbols@1.1.0: - resolution: - { - integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} has-tostringtag@1.0.2: - resolution: - { - integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} has-unicode@2.0.1: - resolution: - { - integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==, - } + resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} hasown@2.0.2: - resolution: - { - integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} he@1.2.0: - resolution: - { - integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==, - } + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true hoist-non-react-statics@3.3.2: - resolution: - { - integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==, - } + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} hosted-git-info@2.8.9: - resolution: - { - integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==, - } + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} hosted-git-info@4.1.0: - resolution: - { - integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} hosted-git-info@7.0.2: - resolution: - { - integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} + engines: {node: ^16.14.0 || >=18.0.0} html-escaper@2.0.2: - resolution: - { - integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==, - } + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} html-minifier@3.5.21: - resolution: - { - integrity: sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==} + engines: {node: '>=4'} hasBin: true htmlparser2@10.0.0: - resolution: - { - integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==, - } + resolution: {integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==} htmlparser2@3.10.1: - resolution: - { - integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==, - } + resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==} htmlparser2@4.1.0: - resolution: - { - integrity: sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==, - } + resolution: {integrity: sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==} http-cache-semantics@4.2.0: - resolution: - { - integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==, - } + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} http-errors@1.7.2: - resolution: - { - integrity: sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==, - } - engines: { node: '>= 0.6' } + resolution: {integrity: sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==} + engines: {node: '>= 0.6'} http-errors@1.8.1: - resolution: - { - integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==, - } - engines: { node: '>= 0.6' } + resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==} + engines: {node: '>= 0.6'} http-errors@2.0.1: - resolution: - { - integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==, - } - engines: { node: '>= 0.8' } + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} http-proxy-agent@7.0.2: - resolution: - { - integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==, - } - engines: { node: '>= 14' } + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} http-signature@1.2.0: - resolution: - { - integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==, - } - engines: { node: '>=0.8', npm: '>=1.3.7' } + resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} + engines: {node: '>=0.8', npm: '>=1.3.7'} https-proxy-agent@7.0.6: - resolution: - { - integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==, - } - engines: { node: '>= 14' } + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} human-signals@2.1.0: - resolution: - { - integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==, - } - engines: { node: '>=10.17.0' } + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} iconv-lite@0.4.24: - resolution: - { - integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} iconv-lite@0.6.3: - resolution: - { - integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} iconv-lite@0.7.1: - resolution: - { - integrity: sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==} + engines: {node: '>=0.10.0'} ieee754@1.2.1: - resolution: - { - integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==, - } + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} ignore-by-default@1.0.1: - resolution: - { - integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==, - } + resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} ignore-walk@6.0.5: - resolution: - { - integrity: sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} ignore@5.3.2: - resolution: - { - integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==, - } - engines: { node: '>= 4' } + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} ignore@7.0.5: - resolution: - { - integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==, - } - engines: { node: '>= 4' } + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} import-fresh@3.3.1: - resolution: - { - integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} import-local@3.1.0: - resolution: - { - integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} + engines: {node: '>=8'} hasBin: true import-local@3.2.0: - resolution: - { - integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} + engines: {node: '>=8'} hasBin: true imurmurhash@0.1.4: - resolution: - { - integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==, - } - engines: { node: '>=0.8.19' } + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} indent-string@4.0.0: - resolution: - { - integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} inflection@3.0.2: - resolution: - { - integrity: sha512-+Bg3+kg+J6JUWn8J6bzFmOWkTQ6L/NHfDRSYU+EVvuKHDxUDHAXgqixHfVlzuBQaPOTac8hn43aPhMNk6rMe3g==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-+Bg3+kg+J6JUWn8J6bzFmOWkTQ6L/NHfDRSYU+EVvuKHDxUDHAXgqixHfVlzuBQaPOTac8hn43aPhMNk6rMe3g==} + engines: {node: '>=18.0.0'} inflekt@0.3.0: - resolution: - { - integrity: sha512-YZRDExCvyQmOYld/oI62icM+V9d7wagwWmJ2+xgV0eAN2fkHR2PoHYDO/tW7BVwhi8viECFJiwdv8dPBSMDzHw==, - } + resolution: {integrity: sha512-YZRDExCvyQmOYld/oI62icM+V9d7wagwWmJ2+xgV0eAN2fkHR2PoHYDO/tW7BVwhi8viECFJiwdv8dPBSMDzHw==} inflekt@0.3.1: - resolution: - { - integrity: sha512-z5jvjelE61KiWinkjlainPDROpO3u0NqlUsCoSTxrSV7yNhcnaIb71ckx3utm8GZ2wifjqGFyaqyYomSXEgMfQ==, - } + resolution: {integrity: sha512-z5jvjelE61KiWinkjlainPDROpO3u0NqlUsCoSTxrSV7yNhcnaIb71ckx3utm8GZ2wifjqGFyaqyYomSXEgMfQ==} inflight@1.0.6: - resolution: - { - integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==, - } + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. inherits@2.0.3: - resolution: - { - integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==, - } + resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} inherits@2.0.4: - resolution: - { - integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==, - } + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} ini@1.3.8: - resolution: - { - integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==, - } + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} ini@4.1.3: - resolution: - { - integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} init-package-json@6.0.3: - resolution: - { - integrity: sha512-Zfeb5ol+H+eqJWHTaGca9BovufyGeIfr4zaaBorPmJBMrJ+KBnN+kQx2ZtXdsotUTgldHmHQV44xvUWOUA7E2w==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-Zfeb5ol+H+eqJWHTaGca9BovufyGeIfr4zaaBorPmJBMrJ+KBnN+kQx2ZtXdsotUTgldHmHQV44xvUWOUA7E2w==} + engines: {node: ^16.14.0 || >=18.0.0} inquirer@8.2.7: - resolution: - { - integrity: sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA==, - } - engines: { node: '>=12.0.0' } + resolution: {integrity: sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA==} + engines: {node: '>=12.0.0'} inquirerer@4.4.0: - resolution: - { - integrity: sha512-zra0M4Oh+rzgr7PMJy9cNi/LbkJbtB6QRABou65nN6NTwb368/lMJ8ACHXozM7bw3+t5SOI0TP3gxKAyT0BCRw==, - } + resolution: {integrity: sha512-zra0M4Oh+rzgr7PMJy9cNi/LbkJbtB6QRABou65nN6NTwb368/lMJ8ACHXozM7bw3+t5SOI0TP3gxKAyT0BCRw==} inquirerer@4.5.0: - resolution: - { - integrity: sha512-ULWscyMV6Y/OH1XRODvunrQH1EO4r7q+UV/boWFiVIt9h2UZ7wa/Qc+ZpAqUaWynKUhDtY3UqZV4MVrRcEkmNg==, - } + resolution: {integrity: sha512-ULWscyMV6Y/OH1XRODvunrQH1EO4r7q+UV/boWFiVIt9h2UZ7wa/Qc+ZpAqUaWynKUhDtY3UqZV4MVrRcEkmNg==} ip-address@10.1.0: - resolution: - { - integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==, - } - engines: { node: '>= 12' } + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} + engines: {node: '>= 12'} ipaddr.js@1.9.1: - resolution: - { - integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==, - } - engines: { node: '>= 0.10' } + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} ipv6-normalize@1.0.1: - resolution: - { - integrity: sha512-Bm6H79i01DjgGTCWjUuCjJ6QDo1HB96PT/xCYuyJUP9WFbVDrLSbG4EZCvOCun2rNswZb0c3e4Jt/ws795esHA==, - } + resolution: {integrity: sha512-Bm6H79i01DjgGTCWjUuCjJ6QDo1HB96PT/xCYuyJUP9WFbVDrLSbG4EZCvOCun2rNswZb0c3e4Jt/ws795esHA==} is-arrayish@0.2.1: - resolution: - { - integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==, - } + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} is-binary-path@2.1.0: - resolution: - { - integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} is-ci@3.0.1: - resolution: - { - integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==, - } + resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} hasBin: true is-core-module@2.16.1: - resolution: - { - integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} is-docker@2.2.1: - resolution: - { - integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} hasBin: true is-extglob@2.1.1: - resolution: - { - integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} is-fullwidth-code-point@3.0.0: - resolution: - { - integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} is-generator-fn@2.1.0: - resolution: - { - integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} is-glob@4.0.3: - resolution: - { - integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} is-interactive@1.0.0: - resolution: - { - integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} is-lambda@1.0.1: - resolution: - { - integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==, - } + resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} is-nan@1.3.2: - resolution: - { - integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} + engines: {node: '>= 0.4'} is-number@7.0.0: - resolution: - { - integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, - } - engines: { node: '>=0.12.0' } + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} is-obj@2.0.0: - resolution: - { - integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} is-plain-obj@1.1.0: - resolution: - { - integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} + engines: {node: '>=0.10.0'} is-plain-object@2.0.4: - resolution: - { - integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} is-promise@4.0.0: - resolution: - { - integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==, - } + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} is-ssh@1.4.1: - resolution: - { - integrity: sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==, - } + resolution: {integrity: sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==} is-stream@2.0.0: - resolution: - { - integrity: sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==} + engines: {node: '>=8'} is-stream@2.0.1: - resolution: - { - integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} is-text-path@1.0.1: - resolution: - { - integrity: sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==} + engines: {node: '>=0.10.0'} is-typedarray@1.0.0: - resolution: - { - integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==, - } + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} is-unicode-supported@0.1.0: - resolution: - { - integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} is-wsl@2.2.0: - resolution: - { - integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} isarray@0.0.1: - resolution: - { - integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==, - } + resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} isarray@1.0.0: - resolution: - { - integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==, - } + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} isexe@2.0.0: - resolution: - { - integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, - } + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} isexe@3.1.1: - resolution: - { - integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==, - } - engines: { node: '>=16' } + resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} + engines: {node: '>=16'} isobject@3.0.1: - resolution: - { - integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} isstream@0.1.2: - resolution: - { - integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==, - } + resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} istanbul-lib-coverage@3.2.2: - resolution: - { - integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} istanbul-lib-instrument@6.0.3: - resolution: - { - integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} + engines: {node: '>=10'} istanbul-lib-report@3.0.1: - resolution: - { - integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==, - } - engines: { node: '>=10' } + 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' } + 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' } + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} + engines: {node: '>=8'} iterall@1.3.0: - resolution: - { - integrity: sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==, - } + resolution: {integrity: sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==} jackspeak@3.4.3: - resolution: - { - integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==, - } - - jackspeak@4.1.1: - resolution: - { - integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==, - } - engines: { node: 20 || >=22 } + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jackspeak@4.2.3: + resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==} + engines: {node: 20 || >=22} jake@10.9.4: - resolution: - { - integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==} + engines: {node: '>=10'} hasBin: true jest-changed-files@30.2.0: - resolution: - { - integrity: sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-circus@30.2.0: - resolution: - { - integrity: sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-cli@30.2.0: - resolution: - { - integrity: sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -9141,11 +6728,8 @@ packages: optional: true jest-config@30.2.0: - resolution: - { - integrity: sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: '@types/node': '*' esbuild-register: '>=3.4.0' @@ -9159,95 +6743,56 @@ packages: optional: true jest-diff@29.7.0: - resolution: - { - integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==, - } - engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} jest-diff@30.2.0: - resolution: - { - integrity: sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-docblock@30.2.0: - resolution: - { - integrity: sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-each@30.2.0: - resolution: - { - integrity: sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-environment-node@30.2.0: - resolution: - { - integrity: sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-get-type@29.6.3: - resolution: - { - integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==, - } - engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} jest-haste-map@30.2.0: - resolution: - { - integrity: sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-in-case@1.0.2: - resolution: - { - integrity: sha512-2DE6Gdwnh5jkCYTePWoQinF+zne3lCADibXoYJEt8PS84JaRug0CyAOrEgzMxbzln3YcSY2PBeru7ct4tbflYA==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-2DE6Gdwnh5jkCYTePWoQinF+zne3lCADibXoYJEt8PS84JaRug0CyAOrEgzMxbzln3YcSY2PBeru7ct4tbflYA==} + engines: {node: '>=4'} jest-leak-detector@30.2.0: - resolution: - { - integrity: sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-matcher-utils@30.2.0: - resolution: - { - integrity: sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-message-util@30.2.0: - resolution: - { - integrity: sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-mock@30.2.0: - resolution: - { - integrity: sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-pnp-resolver@1.2.3: - resolution: - { - integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} peerDependencies: jest-resolve: '*' peerDependenciesMeta: @@ -9255,81 +6800,48 @@ packages: optional: true jest-regex-util@30.0.1: - resolution: - { - integrity: sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-resolve-dependencies@30.2.0: - resolution: - { - integrity: sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-resolve@30.2.0: - resolution: - { - integrity: sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-runner@30.2.0: - resolution: - { - integrity: sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-runtime@30.2.0: - resolution: - { - integrity: sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-snapshot@30.2.0: - resolution: - { - integrity: sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-util@30.2.0: - resolution: - { - integrity: sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-validate@30.2.0: - resolution: - { - integrity: sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-watcher@30.2.0: - resolution: - { - integrity: sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-worker@30.2.0: - resolution: - { - integrity: sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest@30.2.0: - resolution: - { - integrity: sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -9338,1116 +6850,615 @@ packages: optional: true jiti@2.6.1: - resolution: - { - integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==, - } + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true js-beautify@1.15.4: - resolution: - { - integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==} + engines: {node: '>=14'} hasBin: true js-cookie@3.0.5: - resolution: - { - integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} js-sha3@0.8.0: - resolution: - { - integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==, - } + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} js-tokens@4.0.0: - resolution: - { - integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, - } + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} js-yaml@3.14.2: - resolution: - { - integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==, - } + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} hasBin: true js-yaml@4.1.0: - resolution: - { - integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==, - } + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true js-yaml@4.1.1: - resolution: - { - integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==, - } + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true jsbn@0.1.1: - resolution: - { - integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==, - } + resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} jsesc@3.1.0: - resolution: - { - integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} hasBin: true json-buffer@3.0.1: - resolution: - { - integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==, - } + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} json-parse-better-errors@1.0.2: - resolution: - { - integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==, - } + resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} json-parse-even-better-errors@2.3.1: - resolution: - { - integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==, - } + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} json-parse-even-better-errors@3.0.2: - resolution: - { - integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} json-schema-traverse@0.4.1: - resolution: - { - integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==, - } + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} json-schema-traverse@1.0.0: - resolution: - { - integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==, - } + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} json-schema@0.4.0: - resolution: - { - integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==, - } + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} json-stable-stringify-without-jsonify@1.0.1: - resolution: - { - integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==, - } + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} json-stringify-nice@1.1.4: - resolution: - { - integrity: sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==, - } + resolution: {integrity: sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==} json-stringify-safe@5.0.1: - resolution: - { - integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==, - } + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} json5@2.2.3: - resolution: - { - integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} hasBin: true jsonc-parser@3.2.0: - resolution: - { - integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==, - } + resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} jsonfile@6.2.0: - resolution: - { - integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==, - } + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} jsonparse@1.3.1: - resolution: - { - integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==, - } - engines: { '0': node >= 0.2.0 } + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} jsonwebtoken@9.0.3: - resolution: - { - integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==, - } - engines: { node: '>=12', npm: '>=6' } + resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} + engines: {node: '>=12', npm: '>=6'} jsprim@1.4.2: - resolution: - { - integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==, - } - engines: { node: '>=0.6.0' } + resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} + engines: {node: '>=0.6.0'} juice@7.0.0: - resolution: - { - integrity: sha512-AjKQX31KKN+uJs+zaf+GW8mBO/f/0NqSh2moTMyvwBY+4/lXIYTU8D8I2h6BAV3Xnz6GGsbalUyFqbYMe+Vh+Q==, - } - engines: { node: '>=10.0.0' } + resolution: {integrity: sha512-AjKQX31KKN+uJs+zaf+GW8mBO/f/0NqSh2moTMyvwBY+4/lXIYTU8D8I2h6BAV3Xnz6GGsbalUyFqbYMe+Vh+Q==} + engines: {node: '>=10.0.0'} hasBin: true just-diff-apply@5.5.0: - resolution: - { - integrity: sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==, - } + resolution: {integrity: sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==} just-diff@6.0.2: - resolution: - { - integrity: sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA==, - } + resolution: {integrity: sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA==} jwa@2.0.1: - resolution: - { - integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==, - } + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} jws@4.0.1: - resolution: - { - integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==, - } + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} keyv@4.5.4: - resolution: - { - integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==, - } + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} kind-of@6.0.3: - resolution: - { - integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} komoji@0.8.0: - resolution: - { - integrity: sha512-+Ud4ubAJhhTWneLv8V/1OyrQMwrK7ZCHDY7QJJBjaypvTCM8+ECCfKWVZrYz5NIcswuBfiYsDNYJ5kxGUwsoOw==, - } + resolution: {integrity: sha512-+Ud4ubAJhhTWneLv8V/1OyrQMwrK7ZCHDY7QJJBjaypvTCM8+ECCfKWVZrYz5NIcswuBfiYsDNYJ5kxGUwsoOw==} lerna@8.2.4: - resolution: - { - integrity: sha512-0gaVWDIVT7fLfprfwpYcQajb7dBJv3EGavjG7zvJ+TmGx3/wovl5GklnSwM2/WeE0Z2wrIz7ndWhBcDUHVjOcQ==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-0gaVWDIVT7fLfprfwpYcQajb7dBJv3EGavjG7zvJ+TmGx3/wovl5GklnSwM2/WeE0Z2wrIz7ndWhBcDUHVjOcQ==} + engines: {node: '>=18.0.0'} hasBin: true leven@3.1.0: - resolution: - { - integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} levn@0.4.1: - resolution: - { - integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==, - } - engines: { node: '>= 0.8.0' } + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} libnpmaccess@8.0.6: - resolution: - { - integrity: sha512-uM8DHDEfYG6G5gVivVl+yQd4pH3uRclHC59lzIbSvy7b5FEwR+mU49Zq1jEyRtRFv7+M99mUW9S0wL/4laT4lw==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-uM8DHDEfYG6G5gVivVl+yQd4pH3uRclHC59lzIbSvy7b5FEwR+mU49Zq1jEyRtRFv7+M99mUW9S0wL/4laT4lw==} + engines: {node: ^16.14.0 || >=18.0.0} libnpmpublish@9.0.9: - resolution: - { - integrity: sha512-26zzwoBNAvX9AWOPiqqF6FG4HrSCPsHFkQm7nT+xU1ggAujL/eae81RnCv4CJ2In9q9fh10B88sYSzKCUh/Ghg==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-26zzwoBNAvX9AWOPiqqF6FG4HrSCPsHFkQm7nT+xU1ggAujL/eae81RnCv4CJ2In9q9fh10B88sYSzKCUh/Ghg==} + engines: {node: ^16.14.0 || >=18.0.0} libpg-query@17.7.3: - resolution: - { - integrity: sha512-lHKBvoWRsXt/9bJxpAeFxkLu0CA6tELusqy3o1z6/DwGXSETxhKJDaNlNdrNV8msvXDLBhpg/4RE/fKKs5rYFA==, - } + resolution: {integrity: sha512-lHKBvoWRsXt/9bJxpAeFxkLu0CA6tELusqy3o1z6/DwGXSETxhKJDaNlNdrNV8msvXDLBhpg/4RE/fKKs5rYFA==} lines-and-columns@1.2.4: - resolution: - { - integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, - } + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} lines-and-columns@2.0.3: - resolution: - { - integrity: sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==, - } - engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + resolution: {integrity: sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} load-json-file@4.0.0: - resolution: - { - integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} + engines: {node: '>=4'} load-json-file@6.2.0: - resolution: - { - integrity: sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==} + engines: {node: '>=8'} locate-path@2.0.0: - resolution: - { - integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} + engines: {node: '>=4'} locate-path@5.0.0: - resolution: - { - integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} locate-path@6.0.0: - resolution: - { - integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} lodash.includes@4.3.0: - resolution: - { - integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==, - } + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} lodash.isboolean@3.0.3: - resolution: - { - integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==, - } + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} lodash.isinteger@4.0.4: - resolution: - { - integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==, - } + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} lodash.ismatch@4.4.0: - resolution: - { - integrity: sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==, - } + resolution: {integrity: sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==} lodash.isnumber@3.0.3: - resolution: - { - integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==, - } + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} lodash.isplainobject@4.0.6: - resolution: - { - integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==, - } + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} lodash.isstring@4.0.1: - resolution: - { - integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==, - } + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} lodash.memoize@4.1.2: - resolution: - { - integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==, - } + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} lodash.merge@4.6.2: - resolution: - { - integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==, - } + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} lodash.once@4.1.1: - resolution: - { - integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==, - } + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} lodash@4.17.21: - resolution: - { - integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==, - } + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} log-symbols@4.1.0: - resolution: - { - integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} long-timeout@0.1.1: - resolution: - { - integrity: sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==, - } + resolution: {integrity: sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==} long@5.3.2: - resolution: - { - integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==, - } + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} loose-envify@1.4.0: - resolution: - { - integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==, - } + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true lower-case@1.1.4: - resolution: - { - integrity: sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==, - } + resolution: {integrity: sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==} lru-cache@10.4.3: - resolution: - { - integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==, - } + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} lru-cache@11.2.4: - resolution: - { - integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==, - } - engines: { node: 20 || >=22 } + resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} + engines: {node: 20 || >=22} lru-cache@4.1.5: - resolution: - { - integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==, - } + resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} lru-cache@5.1.1: - resolution: - { - integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, - } + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} lru-cache@6.0.0: - resolution: - { - integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} lz-string@1.5.0: - resolution: - { - integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==, - } + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true mailgun.js@10.4.0: - resolution: - { - integrity: sha512-YrdaZEAJwwjXGBTfZTNQ1LM7tmkdUaz2NpZEu7+zULcG4Wrlhd7cWSNZW0bxT3bP48k5N0mZWz8C2f9gc2+Geg==, - } - engines: { node: '>=18.0.0' } - - makage@0.1.10: - resolution: - { - integrity: sha512-IQKuRbHOrDgVNlydle+XRO5iMyaozBq4Bb9vhEzwxtvzyk08JkQo5qpfFRep0dSum53gECdX2gBoTmkWDHIfJA==, - } + resolution: {integrity: sha512-YrdaZEAJwwjXGBTfZTNQ1LM7tmkdUaz2NpZEu7+zULcG4Wrlhd7cWSNZW0bxT3bP48k5N0mZWz8C2f9gc2+Geg==} + engines: {node: '>=18.0.0'} + + makage@0.1.12: + resolution: {integrity: sha512-R3bITl50Ts2GzoaErywe8n24Iu2qbvbNOqOyidjDjh6iqK0CAj2VzIk3xRS4z8Q4xDQzaJrcb2+dGDjqRj6ChA==} hasBin: true make-dir@2.1.0: - resolution: - { - integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} + engines: {node: '>=6'} make-dir@4.0.0: - resolution: - { - integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} make-error@1.3.6: - resolution: - { - integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==, - } + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} make-fetch-happen@13.0.1: - resolution: - { - integrity: sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==} + engines: {node: ^16.14.0 || >=18.0.0} makeerror@1.0.12: - resolution: - { - integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==, - } + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} map-obj@1.0.1: - resolution: - { - integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} + engines: {node: '>=0.10.0'} map-obj@4.3.0: - resolution: - { - integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} + engines: {node: '>=8'} match-sorter@6.3.4: - resolution: - { - integrity: sha512-jfZW7cWS5y/1xswZo8VBOdudUiSd9nifYRWphc9M5D/ee4w4AoXLgBEdRbgVaxbMuagBPeUC5y2Hi8DO6o9aDg==, - } + resolution: {integrity: sha512-jfZW7cWS5y/1xswZo8VBOdudUiSd9nifYRWphc9M5D/ee4w4AoXLgBEdRbgVaxbMuagBPeUC5y2Hi8DO6o9aDg==} math-intrinsics@1.1.0: - resolution: - { - integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==, - } - engines: { node: '>= 0.4' } + 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' } + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} media-typer@1.1.0: - resolution: - { - integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==, - } - engines: { node: '>= 0.8' } + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} mensch@0.3.4: - resolution: - { - integrity: sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==, - } + resolution: {integrity: sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==} meow@8.1.2: - resolution: - { - integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==} + engines: {node: '>=10'} merge-descriptors@2.0.0: - resolution: - { - integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} merge-stream@2.0.0: - resolution: - { - integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==, - } + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} merge2@1.4.1: - resolution: - { - integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==, - } - engines: { node: '>= 8' } + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} methods@1.1.2: - resolution: - { - integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==, - } - engines: { node: '>= 0.6' } + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} micromatch@4.0.8: - resolution: - { - integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==, - } - engines: { node: '>=8.6' } + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} microseconds@0.2.0: - resolution: - { - integrity: sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==, - } + resolution: {integrity: sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==} mime-db@1.52.0: - resolution: - { - integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==, - } - engines: { node: '>= 0.6' } + 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' } + 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' } + 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' } + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} mime@2.6.0: - resolution: - { - integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==, - } - engines: { node: '>=4.0.0' } + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} hasBin: true mimic-fn@2.1.0: - resolution: - { - integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} min-indent@1.0.1: - resolution: - { - integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} minimatch@10.1.1: - resolution: - { - integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==, - } - engines: { node: 20 || >=22 } + resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} + engines: {node: 20 || >=22} + + minimatch@10.1.2: + resolution: {integrity: sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==} + engines: {node: 20 || >=22} minimatch@3.0.5: - resolution: - { - integrity: sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==, - } + resolution: {integrity: sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==} minimatch@3.1.2: - resolution: - { - integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, - } + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} minimatch@5.1.6: - resolution: - { - integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} minimatch@8.0.4: - resolution: - { - integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==, - } - engines: { node: '>=16 || 14 >=14.17' } + resolution: {integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==} + engines: {node: '>=16 || 14 >=14.17'} minimatch@9.0.1: - resolution: - { - integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==, - } - engines: { node: '>=16 || 14 >=14.17' } + resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==} + engines: {node: '>=16 || 14 >=14.17'} minimatch@9.0.3: - resolution: - { - integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==, - } - engines: { node: '>=16 || 14 >=14.17' } + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} minimatch@9.0.5: - resolution: - { - integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==, - } - engines: { node: '>=16 || 14 >=14.17' } + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} minimist-options@4.1.0: - resolution: - { - integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==, - } - engines: { node: '>= 6' } + resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} + engines: {node: '>= 6'} minimist@1.2.8: - resolution: - { - integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, - } + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} minipass-collect@2.0.1: - resolution: - { - integrity: sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==, - } - engines: { node: '>=16 || 14 >=14.17' } + resolution: {integrity: sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==} + engines: {node: '>=16 || 14 >=14.17'} minipass-fetch@3.0.5: - resolution: - { - integrity: sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} minipass-flush@1.0.5: - resolution: - { - integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==, - } - engines: { node: '>= 8' } + resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} + engines: {node: '>= 8'} minipass-pipeline@1.2.4: - resolution: - { - integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} + engines: {node: '>=8'} minipass-sized@1.0.3: - resolution: - { - integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} + engines: {node: '>=8'} minipass@3.3.6: - resolution: - { - integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} minipass@4.2.8: - resolution: - { - integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==} + engines: {node: '>=8'} minipass@5.0.0: - resolution: - { - integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} minipass@7.1.2: - resolution: - { - integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==, - } - engines: { node: '>=16 || 14 >=14.17' } + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} minizlib@2.1.2: - resolution: - { - integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==, - } - engines: { node: '>= 8' } + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} mjml-accordion@4.7.1: - resolution: - { - integrity: sha512-oYwC/CLOUWJ6pRt2saDHj/HytGOHO5B5lKNqUAhKPye5HFNZykKEV5ChmZ2NfGsGU+9BhQ7H5DaCafp4fDmPAg==, - } + resolution: {integrity: sha512-oYwC/CLOUWJ6pRt2saDHj/HytGOHO5B5lKNqUAhKPye5HFNZykKEV5ChmZ2NfGsGU+9BhQ7H5DaCafp4fDmPAg==} mjml-body@4.7.1: - resolution: - { - integrity: sha512-JCrkit+kjCfQyKuVyWSOonM2LGs/o3+63R9l2SleFeXf3+0CaKWaZr/Exzvaeo28c+1o3yRqXbJIpD22SEtJfQ==, - } + resolution: {integrity: sha512-JCrkit+kjCfQyKuVyWSOonM2LGs/o3+63R9l2SleFeXf3+0CaKWaZr/Exzvaeo28c+1o3yRqXbJIpD22SEtJfQ==} mjml-button@4.7.1: - resolution: - { - integrity: sha512-N3WkTMPOvKw2y6sakt1YfYDbOB8apumm1OApPG6J18CHcrX03BwhHPrdfu1JwlRNGwx4kCDdb6zNCGPwuZxkCg==, - } + resolution: {integrity: sha512-N3WkTMPOvKw2y6sakt1YfYDbOB8apumm1OApPG6J18CHcrX03BwhHPrdfu1JwlRNGwx4kCDdb6zNCGPwuZxkCg==} mjml-carousel@4.7.1: - resolution: - { - integrity: sha512-eH3rRyX23ES0BKOn+UUV39+yGNmZVApBVVV0A5znDaNWskCg6/g6ZhEHi4nkWpj+aP2lJKI0HX1nrMfJg0Mxhg==, - } + resolution: {integrity: sha512-eH3rRyX23ES0BKOn+UUV39+yGNmZVApBVVV0A5znDaNWskCg6/g6ZhEHi4nkWpj+aP2lJKI0HX1nrMfJg0Mxhg==} mjml-cli@4.7.1: - resolution: - { - integrity: sha512-xzCtJVKYVhGorvTmnbcMUfZlmJdBnu1UBD9A1H8UUBGMNE/Hs9QpHs9PLCMp8JR/uhSu15IgVjhFN0oSVndMRQ==, - } + resolution: {integrity: sha512-xzCtJVKYVhGorvTmnbcMUfZlmJdBnu1UBD9A1H8UUBGMNE/Hs9QpHs9PLCMp8JR/uhSu15IgVjhFN0oSVndMRQ==} hasBin: true mjml-column@4.7.1: - resolution: - { - integrity: sha512-CGw81TnGiuPR1GblLOez8xeoeAz1SEFjMpqapazjgXUuF5xUxg3qH55Wt4frpXe3VypeZWVYeumr6CwoNaPbKg==, - } + resolution: {integrity: sha512-CGw81TnGiuPR1GblLOez8xeoeAz1SEFjMpqapazjgXUuF5xUxg3qH55Wt4frpXe3VypeZWVYeumr6CwoNaPbKg==} mjml-core@4.7.1: - resolution: - { - integrity: sha512-AMACoq/h440m7SM86As8knW0bNQgjNIzsP/cMF6X9RO07GfszgbaWUq/XCaRNi+q8bWvBJSCXbngDJySVc5ALw==, - } + resolution: {integrity: sha512-AMACoq/h440m7SM86As8knW0bNQgjNIzsP/cMF6X9RO07GfszgbaWUq/XCaRNi+q8bWvBJSCXbngDJySVc5ALw==} mjml-divider@4.7.1: - resolution: - { - integrity: sha512-7+uCUJdqEr6w8AzpF8lhRheelYEgOwiK0KJGlAQN3LF+h2S1rTPEzEB67qL2x5cU+80kPlxtxoQWImDBy0vXqg==, - } + resolution: {integrity: sha512-7+uCUJdqEr6w8AzpF8lhRheelYEgOwiK0KJGlAQN3LF+h2S1rTPEzEB67qL2x5cU+80kPlxtxoQWImDBy0vXqg==} mjml-group@4.7.1: - resolution: - { - integrity: sha512-mAYdhocCzetdhPSws/9/sQ4hcz4kQPX2dNitQmbxNVwoMFYXjp/WcLEfGc5u13Ue7dPfcV6c9lB/Uu5o3NmRvw==, - } + resolution: {integrity: sha512-mAYdhocCzetdhPSws/9/sQ4hcz4kQPX2dNitQmbxNVwoMFYXjp/WcLEfGc5u13Ue7dPfcV6c9lB/Uu5o3NmRvw==} mjml-head-attributes@4.7.1: - resolution: - { - integrity: sha512-nB/bQ3I98Dvy/IkI4nqxTCnLonULkIKc8KrieRTrtPkUV3wskBzngpCgnjKvFPbHWiGlwjHDzcFJc7G0uWeqog==, - } + resolution: {integrity: sha512-nB/bQ3I98Dvy/IkI4nqxTCnLonULkIKc8KrieRTrtPkUV3wskBzngpCgnjKvFPbHWiGlwjHDzcFJc7G0uWeqog==} mjml-head-breakpoint@4.7.1: - resolution: - { - integrity: sha512-0KB5SweIWDvwHkn4VCUsEhCQgfY/0wkNUnSXNoftaRujv0NQFQfOOH4eINy0NZYfDfrE4WYe08z+olHprp+T2A==, - } + resolution: {integrity: sha512-0KB5SweIWDvwHkn4VCUsEhCQgfY/0wkNUnSXNoftaRujv0NQFQfOOH4eINy0NZYfDfrE4WYe08z+olHprp+T2A==} mjml-head-font@4.7.1: - resolution: - { - integrity: sha512-9YGzBcQ2htZ6j266fiLLfzcxqDEDLTvfKtypTjaeRb1w3N8S5wL+/zJA5ZjRL6r39Ij5ZPQSlSDC32KPiwhGkA==, - } + resolution: {integrity: sha512-9YGzBcQ2htZ6j266fiLLfzcxqDEDLTvfKtypTjaeRb1w3N8S5wL+/zJA5ZjRL6r39Ij5ZPQSlSDC32KPiwhGkA==} mjml-head-html-attributes@4.7.1: - resolution: - { - integrity: sha512-2TK2nGpq4rGaghbVx2UNm5TXeZ5BTGYEvtSPoYPNu02KRCj6tb+uedAgFXwJpX+ogRfIfPK50ih+9ZMoHwf2IQ==, - } + resolution: {integrity: sha512-2TK2nGpq4rGaghbVx2UNm5TXeZ5BTGYEvtSPoYPNu02KRCj6tb+uedAgFXwJpX+ogRfIfPK50ih+9ZMoHwf2IQ==} mjml-head-preview@4.7.1: - resolution: - { - integrity: sha512-UHlvvgldiPDODq/5zKMsmXgRb/ZyKygKDUVQSM5bm3HvpKXeyYxJZazcIGmlGICEqv1ced1WGINhCg72dSfN+Q==, - } + resolution: {integrity: sha512-UHlvvgldiPDODq/5zKMsmXgRb/ZyKygKDUVQSM5bm3HvpKXeyYxJZazcIGmlGICEqv1ced1WGINhCg72dSfN+Q==} mjml-head-style@4.7.1: - resolution: - { - integrity: sha512-8Gij99puN1SoOx5tGBjgkh4iCpI+zbwGBiB2Y8VwJrwXQxdJ1Qa902dQP5djoFFG39Bthii/48cS/d1bHigGPQ==, - } + resolution: {integrity: sha512-8Gij99puN1SoOx5tGBjgkh4iCpI+zbwGBiB2Y8VwJrwXQxdJ1Qa902dQP5djoFFG39Bthii/48cS/d1bHigGPQ==} mjml-head-title@4.7.1: - resolution: - { - integrity: sha512-vK3r+DApTXw2EoK/fh8dQOsO438Z7Ksy6iBIb7h04x33d4Z41r6+jtgxGXoKFXnjgr8MyLX5HZyyie5obW+hZg==, - } + resolution: {integrity: sha512-vK3r+DApTXw2EoK/fh8dQOsO438Z7Ksy6iBIb7h04x33d4Z41r6+jtgxGXoKFXnjgr8MyLX5HZyyie5obW+hZg==} mjml-head@4.7.1: - resolution: - { - integrity: sha512-jUcJ674CT1oT8NTQWTjQQBFZu4yklK0oppfGFJ1cq76ze3isMiyhSnGnOHw6FkjLnZtb3gXXaGKX7UZM+UMk/w==, - } + resolution: {integrity: sha512-jUcJ674CT1oT8NTQWTjQQBFZu4yklK0oppfGFJ1cq76ze3isMiyhSnGnOHw6FkjLnZtb3gXXaGKX7UZM+UMk/w==} mjml-hero@4.7.1: - resolution: - { - integrity: sha512-x+29V8zJAs8EV/eTtGbR921pCpitMQOAkyvNANW/3JLDTL2Oio1OYvGPVC3z1wOT9LKuRTxVzNHVt/bBw02CSQ==, - } + resolution: {integrity: sha512-x+29V8zJAs8EV/eTtGbR921pCpitMQOAkyvNANW/3JLDTL2Oio1OYvGPVC3z1wOT9LKuRTxVzNHVt/bBw02CSQ==} mjml-image@4.7.1: - resolution: - { - integrity: sha512-l3uRR2jaM0Bpz4ctdWuxQUFgg+ol6Nt+ODOrnHsGMwpmFOh4hTPTky6KaF0LCXxYmGbI0FoGBna+hVNnkBsQCA==, - } + resolution: {integrity: sha512-l3uRR2jaM0Bpz4ctdWuxQUFgg+ol6Nt+ODOrnHsGMwpmFOh4hTPTky6KaF0LCXxYmGbI0FoGBna+hVNnkBsQCA==} mjml-migrate@4.7.1: - resolution: - { - integrity: sha512-RgrJ9fHg6iRHC2H4pjRDWilBQ1eTH2jRu1ayDplbnepGoql83vLZaYaWc5Q+J+NsaNI16x+bgNB3fQdBiK+mng==, - } + resolution: {integrity: sha512-RgrJ9fHg6iRHC2H4pjRDWilBQ1eTH2jRu1ayDplbnepGoql83vLZaYaWc5Q+J+NsaNI16x+bgNB3fQdBiK+mng==} hasBin: true mjml-navbar@4.7.1: - resolution: - { - integrity: sha512-awdu8zT7xhS+9aCVunqtocUs8KA2xb+UhJ8UGbxVBpYbTNj3rCL9aWUXqWVwMk1la+3ypCkFuDuTl6dIoWPWlA==, - } + resolution: {integrity: sha512-awdu8zT7xhS+9aCVunqtocUs8KA2xb+UhJ8UGbxVBpYbTNj3rCL9aWUXqWVwMk1la+3ypCkFuDuTl6dIoWPWlA==} mjml-parser-xml@4.7.1: - resolution: - { - integrity: sha512-UWfuRpN45k3GUEv2yl8n5Uf98Tg6FyCsyRnqZGo83mgZzlJRDYTdKII9RjZM646/S8+Q8e9qxi3AsL00j6sZsQ==, - } + resolution: {integrity: sha512-UWfuRpN45k3GUEv2yl8n5Uf98Tg6FyCsyRnqZGo83mgZzlJRDYTdKII9RjZM646/S8+Q8e9qxi3AsL00j6sZsQ==} mjml-raw@4.7.1: - resolution: - { - integrity: sha512-mCQFEXINTkC8i7ydP1Km99e0FaZTeu79AoYnTBAILd4QO+RuD3n/PimBGrcGrOUex0JIKa2jyVQOcSCBuG4WpA==, - } + resolution: {integrity: sha512-mCQFEXINTkC8i7ydP1Km99e0FaZTeu79AoYnTBAILd4QO+RuD3n/PimBGrcGrOUex0JIKa2jyVQOcSCBuG4WpA==} mjml-react@1.0.59: - resolution: - { - integrity: sha512-W1ULnMlxJHE0kNpInu+u3CHr6+QcvhoLJ2ov93Pzt2A1wXAv4CJ9T/P5h/BhZn8vvCXgGizcwHv8sfANfQONVw==, - } + resolution: {integrity: sha512-W1ULnMlxJHE0kNpInu+u3CHr6+QcvhoLJ2ov93Pzt2A1wXAv4CJ9T/P5h/BhZn8vvCXgGizcwHv8sfANfQONVw==} peerDependencies: mjml: ^4.1.2 react: ^16.4.0 react-dom: ^16.4.0 mjml-section@4.7.1: - resolution: - { - integrity: sha512-PlhCMsl/bpFwwgQGUopi9OgOGWgRPpEJVKE8hk4He8GXzbfIuDj4DZ9QJSkwIoZ0fZtcgz11Wwb19i9BZcozVw==, - } + resolution: {integrity: sha512-PlhCMsl/bpFwwgQGUopi9OgOGWgRPpEJVKE8hk4He8GXzbfIuDj4DZ9QJSkwIoZ0fZtcgz11Wwb19i9BZcozVw==} mjml-social@4.7.1: - resolution: - { - integrity: sha512-tN/6V3m59izO9rqWpUokHxhwkk2GHkltzIlhI936hAJHh8hFyEO6+ZwQBZm738G00qgfICmQvX5FNq4upkCYjw==, - } + resolution: {integrity: sha512-tN/6V3m59izO9rqWpUokHxhwkk2GHkltzIlhI936hAJHh8hFyEO6+ZwQBZm738G00qgfICmQvX5FNq4upkCYjw==} mjml-spacer@4.7.1: - resolution: - { - integrity: sha512-gQu1+nA9YGnoolfNPvzfVe/RJ8WqS8ho0hthlhiLOC2RnEnmqH7HHSzCFXm4OeN0VgvDQsM7mfYQGl82O58Y+g==, - } + resolution: {integrity: sha512-gQu1+nA9YGnoolfNPvzfVe/RJ8WqS8ho0hthlhiLOC2RnEnmqH7HHSzCFXm4OeN0VgvDQsM7mfYQGl82O58Y+g==} mjml-table@4.7.1: - resolution: - { - integrity: sha512-rPkOtufMiVreb7I7vXk6rDm9i1DXncODnM5JJNhA9Z1dAQwXiz6V5904gAi2cEYfe0M2m0XQ8P5ZCtvqxGkfGA==, - } + resolution: {integrity: sha512-rPkOtufMiVreb7I7vXk6rDm9i1DXncODnM5JJNhA9Z1dAQwXiz6V5904gAi2cEYfe0M2m0XQ8P5ZCtvqxGkfGA==} mjml-text@4.7.1: - resolution: - { - integrity: sha512-hrjxbY59v6hu/Pn0NO+6TMlrdAlRa3M7GVALx/YWYV3hi59zjYfot8Au7Xq64XdcbcI4eiBVbP/AVr8w03HsOw==, - } + resolution: {integrity: sha512-hrjxbY59v6hu/Pn0NO+6TMlrdAlRa3M7GVALx/YWYV3hi59zjYfot8Au7Xq64XdcbcI4eiBVbP/AVr8w03HsOw==} mjml-validator@4.7.1: - resolution: - { - integrity: sha512-Qxubbz5WE182iLSTd/XRuezMr6UE7/u73grDCw0bTIcQsaTAIkWQn2tBI3jj0chWOw+sxwK2C6zPm9B0Cv7BGA==, - } + resolution: {integrity: sha512-Qxubbz5WE182iLSTd/XRuezMr6UE7/u73grDCw0bTIcQsaTAIkWQn2tBI3jj0chWOw+sxwK2C6zPm9B0Cv7BGA==} mjml-wrapper@4.7.1: - resolution: - { - integrity: sha512-6i+ZATUyqIO5YBnx+RFKZ3+6mg3iOCS/EdXGYZSonZ/EHqlt+RJa3fG2BB4dacXqAjghfl6Lk+bLoR47P3xYIQ==, - } + resolution: {integrity: sha512-6i+ZATUyqIO5YBnx+RFKZ3+6mg3iOCS/EdXGYZSonZ/EHqlt+RJa3fG2BB4dacXqAjghfl6Lk+bLoR47P3xYIQ==} mjml@4.7.1: - resolution: - { - integrity: sha512-nwMrmhTI+Aeh9Gav9LHX/i8k8yDi/QpX5h535BlT5oP4NaAUmyxP/UeYUn9yxtPcIzDlM5ullFnRv/71jyHpkQ==, - } + resolution: {integrity: sha512-nwMrmhTI+Aeh9Gav9LHX/i8k8yDi/QpX5h535BlT5oP4NaAUmyxP/UeYUn9yxtPcIzDlM5ullFnRv/71jyHpkQ==} hasBin: true mkdirp@1.0.4: - resolution: - { - integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} hasBin: true mock-req@0.2.0: - resolution: - { - integrity: sha512-IUuwS0W5GjoPyjhuXPQJXpaHfHW7UYFRia8Cchm/xRuyDDclpSQdEoakt3krOpSYvgVlQsbnf0ePDsTRDfp7Dg==, - } + resolution: {integrity: sha512-IUuwS0W5GjoPyjhuXPQJXpaHfHW7UYFRia8Cchm/xRuyDDclpSQdEoakt3krOpSYvgVlQsbnf0ePDsTRDfp7Dg==} modify-values@1.0.1: - resolution: - { - integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==} + engines: {node: '>=0.10.0'} moment-timezone@0.5.48: - resolution: - { - integrity: sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw==, - } + resolution: {integrity: sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw==} moment@2.30.1: - resolution: - { - integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==, - } + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} ms@2.0.0: - resolution: - { - integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==, - } + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} ms@2.1.3: - resolution: - { - integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, - } + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} multimatch@5.0.0: - resolution: - { - integrity: sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==} + engines: {node: '>=10'} mute-stream@0.0.8: - resolution: - { - integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==, - } + resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} mute-stream@1.0.0: - resolution: - { - integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} nano-time@1.0.0: - resolution: - { - integrity: sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==, - } + resolution: {integrity: sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true napi-postinstall@0.3.4: - resolution: - { - integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==, - } - engines: { node: ^12.20.0 || ^14.18.0 || >=16.0.0 } + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} hasBin: true natural-compare@1.4.0: - resolution: - { - integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==, - } + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} negotiator@0.6.4: - resolution: - { - integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==, - } - engines: { node: '>= 0.6' } + resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} + engines: {node: '>= 0.6'} negotiator@1.0.0: - resolution: - { - integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==, - } - engines: { node: '>= 0.6' } + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} neo-async@2.6.2: - resolution: - { - integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==, - } + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} nested-obj@0.1.10: - resolution: - { - integrity: sha512-5V2kUPrBee/tmoS2p0IJ35BcaJuW1p1yXF5GP8JpXIkDoPbaYeYypAHizUeZkAUxcC7Rago7izWmEq7qa8+Mhw==, - } + resolution: {integrity: sha512-5V2kUPrBee/tmoS2p0IJ35BcaJuW1p1yXF5GP8JpXIkDoPbaYeYypAHizUeZkAUxcC7Rago7izWmEq7qa8+Mhw==} nested-obj@0.1.5: - resolution: - { - integrity: sha512-04Y7qDMlI8RbYTn0cJAKaw/mLrO9UmLj3xbrjTZKDfOn9f3b/RXEQFIIpveJlwn8KfPwdVFWLZUaL5gNuQ7G0w==, - } + resolution: {integrity: sha512-04Y7qDMlI8RbYTn0cJAKaw/mLrO9UmLj3xbrjTZKDfOn9f3b/RXEQFIIpveJlwn8KfPwdVFWLZUaL5gNuQ7G0w==} nested-obj@0.2.0: - resolution: - { - integrity: sha512-uPzih1V6f7yb563xUkFA/oainPdrlc0ojpV8OuRAg4qWK70TPt14D5hWuU3ta1eVacJQv+VVuMJRqFRyTgYZ0Q==, - } + resolution: {integrity: sha512-uPzih1V6f7yb563xUkFA/oainPdrlc0ojpV8OuRAg4qWK70TPt14D5hWuU3ta1eVacJQv+VVuMJRqFRyTgYZ0Q==} no-case@2.3.2: - resolution: - { - integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==, - } + resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==} node-fetch@2.6.7: - resolution: - { - integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==, - } - engines: { node: 4.x || >=6.0.0 } + resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} + engines: {node: 4.x || >=6.0.0} peerDependencies: encoding: ^0.1.0 peerDependenciesMeta: @@ -10455,11 +7466,8 @@ packages: optional: true node-fetch@2.7.0: - resolution: - { - integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==, - } - engines: { node: 4.x || >=6.0.0 } + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} peerDependencies: encoding: ^0.1.0 peerDependenciesMeta: @@ -10467,173 +7475,98 @@ packages: optional: true node-gyp@10.3.1: - resolution: - { - integrity: sha512-Pp3nFHBThHzVtNY7U6JfPjvT/DTE8+o/4xKsLQtBoU+j2HLsGlhcfzflAoUreaJbNmYnX+LlLi0qjV8kpyO6xQ==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-Pp3nFHBThHzVtNY7U6JfPjvT/DTE8+o/4xKsLQtBoU+j2HLsGlhcfzflAoUreaJbNmYnX+LlLi0qjV8kpyO6xQ==} + engines: {node: ^16.14.0 || >=18.0.0} hasBin: true node-int64@0.4.0: - resolution: - { - integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==, - } + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} node-machine-id@1.1.12: - resolution: - { - integrity: sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==, - } + resolution: {integrity: sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==} node-releases@2.0.27: - resolution: - { - integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==, - } + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} node-schedule@1.3.2: - resolution: - { - integrity: sha512-GIND2pHMHiReSZSvS6dpZcDH7pGPGFfWBIEud6S00Q8zEIzAs9ommdyRK1ZbQt8y1LyZsJYZgPnyi7gpU2lcdw==, - } + resolution: {integrity: sha512-GIND2pHMHiReSZSvS6dpZcDH7pGPGFfWBIEud6S00Q8zEIzAs9ommdyRK1ZbQt8y1LyZsJYZgPnyi7gpU2lcdw==} nodemailer@6.10.1: - resolution: - { - integrity: sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA==, - } - engines: { node: '>=6.0.0' } + resolution: {integrity: sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA==} + engines: {node: '>=6.0.0'} nodemailer@7.0.11: - resolution: - { - integrity: sha512-gnXhNRE0FNhD7wPSCGhdNh46Hs6nm+uTyg+Kq0cZukNQiYdnCsoQjodNP9BQVG9XrcK/v6/MgpAPBUFyzh9pvw==, - } - engines: { node: '>=6.0.0' } + resolution: {integrity: sha512-gnXhNRE0FNhD7wPSCGhdNh46Hs6nm+uTyg+Kq0cZukNQiYdnCsoQjodNP9BQVG9XrcK/v6/MgpAPBUFyzh9pvw==} + engines: {node: '>=6.0.0'} nodemon@3.1.11: - resolution: - { - integrity: sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==} + engines: {node: '>=10'} hasBin: true noms@0.0.0: - resolution: - { - integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==, - } + resolution: {integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==} nopt@7.2.1: - resolution: - { - integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} hasBin: true normalize-package-data@2.5.0: - resolution: - { - integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==, - } + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} normalize-package-data@3.0.3: - resolution: - { - integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} + engines: {node: '>=10'} normalize-package-data@6.0.2: - resolution: - { - integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==} + engines: {node: ^16.14.0 || >=18.0.0} normalize-path@3.0.0: - resolution: - { - integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} npm-bundled@3.0.1: - resolution: - { - integrity: sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} npm-install-checks@6.3.0: - resolution: - { - integrity: sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} npm-normalize-package-bin@3.0.1: - resolution: - { - integrity: sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} npm-package-arg@11.0.2: - resolution: - { - integrity: sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==} + engines: {node: ^16.14.0 || >=18.0.0} npm-packlist@8.0.2: - resolution: - { - integrity: sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} npm-pick-manifest@9.1.0: - resolution: - { - integrity: sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==} + engines: {node: ^16.14.0 || >=18.0.0} npm-registry-fetch@17.1.0: - resolution: - { - integrity: sha512-5+bKQRH0J1xG1uZ1zMNvxW0VEyoNWgJpY9UDuluPFLKDfJ9u2JmmjmTJV1srBGQOROfdBMiVvnH2Zvpbm+xkVA==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-5+bKQRH0J1xG1uZ1zMNvxW0VEyoNWgJpY9UDuluPFLKDfJ9u2JmmjmTJV1srBGQOROfdBMiVvnH2Zvpbm+xkVA==} + engines: {node: ^16.14.0 || >=18.0.0} npm-run-path@4.0.1: - resolution: - { - integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} nth-check@1.0.2: - resolution: - { - integrity: sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==, - } + resolution: {integrity: sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==} nth-check@2.1.1: - resolution: - { - integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==, - } + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} nx@20.8.3: - resolution: - { - integrity: sha512-8w815WSMWar3A/LFzwtmEY+E8cVW62lMiFuPDXje+C8O8hFndfvscP56QHNMn2Zdhz3q0+BZUe+se4Em1BKYdA==, - } + resolution: {integrity: sha512-8w815WSMWar3A/LFzwtmEY+E8cVW62lMiFuPDXje+C8O8hFndfvscP56QHNMn2Zdhz3q0+BZUe+se4Em1BKYdA==} hasBin: true peerDependencies: '@swc-node/register': ^1.8.0 @@ -10645,470 +7578,263 @@ packages: optional: true oauth-sign@0.9.0: - resolution: - { - integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==, - } + resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} object-assign@4.1.1: - resolution: - { - integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, - } - engines: { node: '>=0.10.0' } + 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' } + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} object-keys@1.1.1: - resolution: - { - integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} object-path@0.11.8: - resolution: - { - integrity: sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==, - } - engines: { node: '>= 10.12.0' } + resolution: {integrity: sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==} + engines: {node: '>= 10.12.0'} oblivious-set@1.0.0: - resolution: - { - integrity: sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==, - } + resolution: {integrity: sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==} on-finished@2.3.0: - resolution: - { - integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==, - } - engines: { node: '>= 0.8' } + resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} + engines: {node: '>= 0.8'} on-finished@2.4.1: - resolution: - { - integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==, - } - engines: { node: '>= 0.8' } + 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==, - } + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} onetime@5.1.2: - resolution: - { - integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} open@8.4.2: - resolution: - { - integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==, - } - engines: { node: '>=12' } + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} optionator@0.9.4: - resolution: - { - integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==, - } - engines: { node: '>= 0.8.0' } + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} ora@5.3.0: - resolution: - { - integrity: sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==} + engines: {node: '>=10'} ora@5.4.1: - resolution: - { - integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} oxfmt@0.26.0: - resolution: - { - integrity: sha512-UDD1wFNwfeorMm2ZY0xy1KRAAvJ5NjKBfbDmiMwGP7baEHTq65cYpC0aPP+BGHc8weXUbSZaK8MdGyvuRUvS4Q==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + resolution: {integrity: sha512-UDD1wFNwfeorMm2ZY0xy1KRAAvJ5NjKBfbDmiMwGP7baEHTq65cYpC0aPP+BGHc8weXUbSZaK8MdGyvuRUvS4Q==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true p-finally@1.0.0: - resolution: - { - integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} + engines: {node: '>=4'} p-limit@1.3.0: - resolution: - { - integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} + engines: {node: '>=4'} p-limit@2.3.0: - resolution: - { - integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} p-limit@3.1.0: - resolution: - { - integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} p-locate@2.0.0: - resolution: - { - integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} + engines: {node: '>=4'} p-locate@4.1.0: - resolution: - { - integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} p-locate@5.0.0: - resolution: - { - integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} p-map-series@2.1.0: - resolution: - { - integrity: sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q==} + engines: {node: '>=8'} p-map@4.0.0: - resolution: - { - integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} p-pipe@3.1.0: - resolution: - { - integrity: sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==} + engines: {node: '>=8'} p-queue@6.6.2: - resolution: - { - integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==} + engines: {node: '>=8'} p-reduce@2.1.0: - resolution: - { - integrity: sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==} + engines: {node: '>=8'} p-timeout@3.2.0: - resolution: - { - integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} + engines: {node: '>=8'} p-try@1.0.0: - resolution: - { - integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} + engines: {node: '>=4'} p-try@2.2.0: - resolution: - { - integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} p-waterfall@2.1.1: - resolution: - { - integrity: sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw==} + engines: {node: '>=8'} package-json-from-dist@1.0.1: - resolution: - { - integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==, - } + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} pacote@18.0.6: - resolution: - { - integrity: sha512-+eK3G27SMwsB8kLIuj4h1FUhHtwiEUo21Tw8wNjmvdlpOEr613edv+8FUsTj/4F/VN5ywGE19X18N7CC2EJk6A==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-+eK3G27SMwsB8kLIuj4h1FUhHtwiEUo21Tw8wNjmvdlpOEr613edv+8FUsTj/4F/VN5ywGE19X18N7CC2EJk6A==} + engines: {node: ^16.14.0 || >=18.0.0} hasBin: true param-case@2.1.1: - resolution: - { - integrity: sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==, - } + resolution: {integrity: sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==} parent-module@1.0.1: - resolution: - { - integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} parse-conflict-json@3.0.1: - resolution: - { - integrity: sha512-01TvEktc68vwbJOtWZluyWeVGWjP+bZwXtPDMQVbBKzbJ/vZBif0L69KH1+cHv1SZ6e0FKLvjyHe8mqsIqYOmw==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-01TvEktc68vwbJOtWZluyWeVGWjP+bZwXtPDMQVbBKzbJ/vZBif0L69KH1+cHv1SZ6e0FKLvjyHe8mqsIqYOmw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} parse-json@4.0.0: - resolution: - { - integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} + engines: {node: '>=4'} parse-json@5.2.0: - resolution: - { - integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} parse-package-name@1.0.0: - resolution: - { - integrity: sha512-kBeTUtcj+SkyfaW4+KBe0HtsloBJ/mKTPoxpVdA57GZiPerREsUWJOhVj9anXweFiJkm5y8FG1sxFZkZ0SN6wg==, - } + resolution: {integrity: sha512-kBeTUtcj+SkyfaW4+KBe0HtsloBJ/mKTPoxpVdA57GZiPerREsUWJOhVj9anXweFiJkm5y8FG1sxFZkZ0SN6wg==} parse-path@7.1.0: - resolution: - { - integrity: sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==, - } + resolution: {integrity: sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==} parse-url@8.1.0: - resolution: - { - integrity: sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==, - } + resolution: {integrity: sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==} parse5-htmlparser2-tree-adapter@7.1.0: - resolution: - { - integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==, - } + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} parse5-parser-stream@7.1.2: - resolution: - { - integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==, - } + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} parse5@3.0.3: - resolution: - { - integrity: sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==, - } + resolution: {integrity: sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==} parse5@7.3.0: - resolution: - { - integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==, - } + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} parseurl@1.3.3: - resolution: - { - integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==, - } - engines: { node: '>= 0.8' } + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} path-exists@3.0.0: - resolution: - { - integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} path-exists@4.0.0: - resolution: - { - integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} path-is-absolute@1.0.1: - resolution: - { - integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} path-key@3.1.1: - resolution: - { - integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} path-parse@1.0.7: - resolution: - { - integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, - } + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} path-scurry@1.11.1: - resolution: - { - integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==, - } - engines: { node: '>=16 || 14 >=14.18' } + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} path-scurry@2.0.1: - resolution: - { - integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==, - } - engines: { node: 20 || >=22 } + resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==} + engines: {node: 20 || >=22} path-to-regexp@8.3.0: - resolution: - { - integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==, - } + resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} path-type@3.0.0: - resolution: - { - integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} + engines: {node: '>=4'} performance-now@2.1.0: - resolution: - { - integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==, - } + resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} pg-cloudflare@1.3.0: - resolution: - { - integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==, - } + resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} pg-connection-string@2.10.0: - resolution: - { - integrity: sha512-ur/eoPKzDx2IjPaYyXS6Y8NSblxM7X64deV2ObV57vhjsWiwLvUD6meukAzogiOsu60GO8m/3Cb6FdJsWNjwXg==, - } + resolution: {integrity: sha512-ur/eoPKzDx2IjPaYyXS6Y8NSblxM7X64deV2ObV57vhjsWiwLvUD6meukAzogiOsu60GO8m/3Cb6FdJsWNjwXg==} pg-connection-string@2.9.1: - resolution: - { - integrity: sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==, - } + resolution: {integrity: sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==} pg-copy-streams@7.0.0: - resolution: - { - integrity: sha512-zBvnY6wtaBRE2ae2xXWOOGMaNVPkXh1vhypAkNSKgMdciJeTyIQAHZaEeRAxUjs/p1El5jgzYmwG5u871Zj3dQ==, - } + resolution: {integrity: sha512-zBvnY6wtaBRE2ae2xXWOOGMaNVPkXh1vhypAkNSKgMdciJeTyIQAHZaEeRAxUjs/p1El5jgzYmwG5u871Zj3dQ==} pg-int8@1.0.1: - resolution: - { - integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==, - } - engines: { node: '>=4.0.0' } + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} pg-pool@3.11.0: - resolution: - { - integrity: sha512-MJYfvHwtGp870aeusDh+hg9apvOe2zmpZJpyt+BMtzUWlVqbhFmMK6bOBXLBUPd7iRtIF9fZplDc7KrPN3PN7w==, - } + resolution: {integrity: sha512-MJYfvHwtGp870aeusDh+hg9apvOe2zmpZJpyt+BMtzUWlVqbhFmMK6bOBXLBUPd7iRtIF9fZplDc7KrPN3PN7w==} peerDependencies: pg: '>=8.0' pg-proto-parser@1.30.4: - resolution: - { - integrity: sha512-+9/n8zfYQVNRc8KGhxxNXO8NA5OKni01IPtit6+C3sLMtcRVVFCj4W0XtrEGFivNjz2qwUtFmRhG8OGMTxs6hg==, - } + resolution: {integrity: sha512-+9/n8zfYQVNRc8KGhxxNXO8NA5OKni01IPtit6+C3sLMtcRVVFCj4W0XtrEGFivNjz2qwUtFmRhG8OGMTxs6hg==} pg-protocol@1.10.3: - resolution: - { - integrity: sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==, - } + resolution: {integrity: sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==} pg-protocol@1.11.0: - resolution: - { - integrity: sha512-pfsxk2M9M3BuGgDOfuy37VNRRX3jmKgMjcvAcWqNDpZSf4cUmv8HSOl5ViRQFsfARFn0KuUQTgLxVMbNq5NW3g==, - } + resolution: {integrity: sha512-pfsxk2M9M3BuGgDOfuy37VNRRX3jmKgMjcvAcWqNDpZSf4cUmv8HSOl5ViRQFsfARFn0KuUQTgLxVMbNq5NW3g==} pg-sql2@4.14.1: - resolution: - { - integrity: sha512-DvL0K9Pqz47EFq+BaQlGpzsXJnArKoAbxBxtHLy2/p3ey1X7ZwUF79UwFoDSTxQQCIbR4Z5D8CBI0nPfpw9Tmw==, - } - engines: { node: '>=8.6' } + resolution: {integrity: sha512-DvL0K9Pqz47EFq+BaQlGpzsXJnArKoAbxBxtHLy2/p3ey1X7ZwUF79UwFoDSTxQQCIbR4Z5D8CBI0nPfpw9Tmw==} + engines: {node: '>=8.6'} peerDependencies: pg: '>=6.1.0 <9' pg-tsquery@8.4.2: - resolution: - { - integrity: sha512-waJSlBIKE+shDhuDpuQglTH6dG5zakDhnrnxu8XB8V5c7yoDSuy4pOxY6t2dyoxTjaKMcMmlByJN7n9jx9eqMA==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-waJSlBIKE+shDhuDpuQglTH6dG5zakDhnrnxu8XB8V5c7yoDSuy4pOxY6t2dyoxTjaKMcMmlByJN7n9jx9eqMA==} + engines: {node: '>=10'} pg-types@2.2.0: - resolution: - { - integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} pg@8.17.1: - resolution: - { - integrity: sha512-EIR+jXdYNSMOrpRp7g6WgQr7SaZNZfS7IzZIO0oTNEeibq956JxeD15t3Jk3zZH0KH8DmOIx38qJfQenoE8bXQ==, - } - engines: { node: '>= 16.0.0' } + resolution: {integrity: sha512-EIR+jXdYNSMOrpRp7g6WgQr7SaZNZfS7IzZIO0oTNEeibq956JxeD15t3Jk3zZH0KH8DmOIx38qJfQenoE8bXQ==} + engines: {node: '>= 16.0.0'} peerDependencies: pg-native: '>=3.0.1' peerDependenciesMeta: @@ -11116,240 +7842,142 @@ packages: optional: true pgpass@1.0.5: - resolution: - { - integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==, - } + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} pgsql-deparser@17.17.2: - resolution: - { - integrity: sha512-FCjqKY3Sdmce3VUd3CxCXF0kqaZ0s4a6yIMT5UJ9vETh0cF54A8Tpqjn0qBKaPUD8xqTKeLdS+SfiwjAC64wrA==, - } + resolution: {integrity: sha512-FCjqKY3Sdmce3VUd3CxCXF0kqaZ0s4a6yIMT5UJ9vETh0cF54A8Tpqjn0qBKaPUD8xqTKeLdS+SfiwjAC64wrA==} pgsql-parser@17.9.11: - resolution: - { - integrity: sha512-Bqp9uLvJK0Qht9PXzI6eC/Fn+lFRL+2eMvXss4D4qt7lxPLIHS8FMKYOHUQNTI3m6ylExSOdNXhx/DL5UGm3xg==, - } + resolution: {integrity: sha512-Bqp9uLvJK0Qht9PXzI6eC/Fn+lFRL+2eMvXss4D4qt7lxPLIHS8FMKYOHUQNTI3m6ylExSOdNXhx/DL5UGm3xg==} picocolors@1.1.1: - resolution: - { - integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==, - } + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} picomatch@2.3.1: - resolution: - { - integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, - } - engines: { node: '>=8.6' } + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} picomatch@4.0.3: - resolution: - { - integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==, - } - engines: { node: '>=12' } + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} pify@2.3.0: - resolution: - { - integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} pify@3.0.0: - resolution: - { - integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} + engines: {node: '>=4'} pify@4.0.1: - resolution: - { - integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} pify@5.0.0: - resolution: - { - integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==} + engines: {node: '>=10'} pirates@4.0.7: - resolution: - { - integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==, - } - engines: { node: '>= 6' } + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} pkg-dir@4.2.0: - resolution: - { - integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} playwright-core@1.57.0: - resolution: - { - integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==} + engines: {node: '>=18'} hasBin: true playwright@1.57.0: - resolution: - { - integrity: sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==} + engines: {node: '>=18'} hasBin: true pluralize@7.0.0: - resolution: - { - integrity: sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==} + engines: {node: '>=4'} postcss-selector-parser@6.1.2: - resolution: - { - integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} postcss-value-parser@4.2.0: - resolution: - { - integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==, - } + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} postgraphile-core@4.14.1: - resolution: - { - integrity: sha512-3U6DAoGUmOikl9dVQhSJcw4cLeG0vQQnvEFw7MR0rvn125c1xdv6UBvamvX0pOzSfz5oBrFRQkZ2LvclAXKyBQ==, - } - engines: { node: '>=8.6' } + resolution: {integrity: sha512-3U6DAoGUmOikl9dVQhSJcw4cLeG0vQQnvEFw7MR0rvn125c1xdv6UBvamvX0pOzSfz5oBrFRQkZ2LvclAXKyBQ==} + engines: {node: '>=8.6'} peerDependencies: graphql: '>=0.9 <0.14 || ^14.0.2 || ^15.4.0' pg: '>=6.1.0 <9' postgraphile@4.14.1: - resolution: - { - integrity: sha512-4Rz//TtnjyZk6CbrcypWJNFRwXupHK+bHvaYaX2RrtxMJ2lTaoMDYOdEFESdo/POie3CAEbsC8ZBqb9eR/EyVw==, - } - engines: { node: '>=8.6' } + resolution: {integrity: sha512-4Rz//TtnjyZk6CbrcypWJNFRwXupHK+bHvaYaX2RrtxMJ2lTaoMDYOdEFESdo/POie3CAEbsC8ZBqb9eR/EyVw==} + engines: {node: '>=8.6'} hasBin: true postgres-array@2.0.0: - resolution: - { - integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==, - } - engines: { node: '>=4' } + 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' } + 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' } + 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' } + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} prelude-ls@1.2.1: - resolution: - { - integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==, - } - engines: { node: '>= 0.8.0' } + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} prettier@3.8.0: - resolution: - { - integrity: sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==} + engines: {node: '>=14'} hasBin: true pretty-format@26.6.2: - resolution: - { - integrity: sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==, - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==} + engines: {node: '>= 10'} pretty-format@29.7.0: - resolution: - { - integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==, - } - engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} pretty-format@30.2.0: - resolution: - { - integrity: sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==, - } - engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} proc-log@4.2.0: - resolution: - { - integrity: sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} process-nextick-args@2.0.1: - resolution: - { - integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==, - } + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} proggy@2.0.0: - resolution: - { - integrity: sha512-69agxLtnI8xBs9gUGqEnK26UfiexpHy+KUpBQWabiytQjnn5wFY8rklAi7GRfABIuPNnQ/ik48+LGLkYYJcy4A==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-69agxLtnI8xBs9gUGqEnK26UfiexpHy+KUpBQWabiytQjnn5wFY8rklAi7GRfABIuPNnQ/ik48+LGLkYYJcy4A==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} promise-all-reject-late@1.0.1: - resolution: - { - integrity: sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==, - } + resolution: {integrity: sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==} promise-call-limit@3.0.2: - resolution: - { - integrity: sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw==, - } + resolution: {integrity: sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw==} promise-inflight@1.0.1: - resolution: - { - integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==, - } + resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} peerDependencies: bluebird: '*' peerDependenciesMeta: @@ -11357,175 +7985,100 @@ packages: optional: true promise-retry@2.0.1: - resolution: - { - integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} + engines: {node: '>=10'} promzard@1.0.2: - resolution: - { - integrity: sha512-2FPputGL+mP3jJ3UZg/Dl9YOkovB7DX0oOr+ck5QbZ5MtORtds8k/BZdn+02peDLI8/YWbmzx34k5fA+fHvCVQ==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-2FPputGL+mP3jJ3UZg/Dl9YOkovB7DX0oOr+ck5QbZ5MtORtds8k/BZdn+02peDLI8/YWbmzx34k5fA+fHvCVQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} proto-list@1.2.4: - resolution: - { - integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==, - } + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} protocols@2.0.2: - resolution: - { - integrity: sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==, - } + resolution: {integrity: sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==} proxy-addr@2.0.7: - resolution: - { - integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==, - } - engines: { node: '>= 0.10' } + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} proxy-from-env@1.1.0: - resolution: - { - integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==, - } + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} pseudomap@1.0.2: - resolution: - { - integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==, - } + resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} psl@1.15.0: - resolution: - { - integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==, - } + resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} pstree.remy@1.1.8: - resolution: - { - integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==, - } + resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} punycode.js@2.3.1: - resolution: - { - integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} punycode@2.3.1: - resolution: - { - integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} pure-rand@7.0.1: - resolution: - { - integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==, - } + resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} qs@6.14.0: - resolution: - { - integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==, - } - engines: { node: '>=0.6' } + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} qs@6.14.1: - resolution: - { - integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==, - } - engines: { node: '>=0.6' } + resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} + engines: {node: '>=0.6'} qs@6.5.3: - resolution: - { - integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==, - } - engines: { node: '>=0.6' } + resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} + engines: {node: '>=0.6'} qs@6.7.0: - resolution: - { - integrity: sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==, - } - engines: { node: '>=0.6' } + resolution: {integrity: sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==} + engines: {node: '>=0.6'} queue-microtask@1.2.3: - resolution: - { - integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, - } + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} quick-lru@4.0.1: - resolution: - { - integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} + engines: {node: '>=8'} range-parser@1.2.1: - resolution: - { - integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==, - } - engines: { node: '>= 0.6' } + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} raw-body@2.4.0: - resolution: - { - integrity: sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==, - } - engines: { node: '>= 0.8' } + resolution: {integrity: sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==} + engines: {node: '>= 0.8'} raw-body@3.0.2: - resolution: - { - integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==, - } - engines: { node: '>= 0.10' } + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} react-dom@19.2.3: - resolution: - { - integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==, - } + resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} peerDependencies: react: ^19.2.3 react-is@16.13.1: - resolution: - { - integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==, - } + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} react-is@17.0.2: - resolution: - { - integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==, - } + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} react-is@18.3.1: - resolution: - { - integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==, - } + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-is@19.2.4: + resolution: {integrity: sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA==} react-query@3.39.3: - resolution: - { - integrity: sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g==, - } + resolution: {integrity: sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: '*' @@ -11536,947 +8089,568 @@ packages: react-native: optional: true + react-refresh@0.17.0: + resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} + engines: {node: '>=0.10.0'} + + react-test-renderer@19.2.3: + resolution: {integrity: sha512-TMR1LnSFiWZMJkCgNf5ATSvAheTT2NvKIwiVwdBPHxjBI7n/JbWd4gaZ16DVd9foAXdvDz+sB5yxZTwMjPRxpw==} + peerDependencies: + react: ^19.2.3 + react@19.2.3: - resolution: - { - integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} + engines: {node: '>=0.10.0'} read-cmd-shim@4.0.0: - resolution: - { - integrity: sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} read-package-json-fast@3.0.2: - resolution: - { - integrity: sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} read-pkg-up@3.0.0: - resolution: - { - integrity: sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==} + engines: {node: '>=4'} read-pkg-up@7.0.1: - resolution: - { - integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} + engines: {node: '>=8'} read-pkg@3.0.0: - resolution: - { - integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==} + engines: {node: '>=4'} read-pkg@5.2.0: - resolution: - { - integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} + engines: {node: '>=8'} read@3.0.1: - resolution: - { - integrity: sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} readable-stream@1.0.34: - resolution: - { - integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==, - } + resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} readable-stream@2.3.8: - resolution: - { - integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==, - } + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} readable-stream@3.6.2: - resolution: - { - integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==, - } - engines: { node: '>= 6' } + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} readdirp@3.6.0: - resolution: - { - integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==, - } - engines: { node: '>=8.10.0' } + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} redent@3.0.0: - resolution: - { - integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} regenerator-runtime@0.10.5: - resolution: - { - integrity: sha512-02YopEIhAgiBHWeoTiA8aitHDt8z6w+rQqNuIftlM+ZtvSl/brTouaU7DW6GO/cHtvxJvS4Hwv2ibKdxIRi24w==, - } + resolution: {integrity: sha512-02YopEIhAgiBHWeoTiA8aitHDt8z6w+rQqNuIftlM+ZtvSl/brTouaU7DW6GO/cHtvxJvS4Hwv2ibKdxIRi24w==} relateurl@0.2.7: - resolution: - { - integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==, - } - engines: { node: '>= 0.10' } + resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==} + engines: {node: '>= 0.10'} remove-accents@0.5.0: - resolution: - { - integrity: sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==, - } + resolution: {integrity: sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==} request-ip@3.3.0: - resolution: - { - integrity: sha512-cA6Xh6e0fDBBBwH77SLJaJPBmD3nWVAcF9/XAcsrIHdjhFzFiB5aNQFytdjCGPezU3ROwrR11IddKAM08vohxA==, - } + resolution: {integrity: sha512-cA6Xh6e0fDBBBwH77SLJaJPBmD3nWVAcF9/XAcsrIHdjhFzFiB5aNQFytdjCGPezU3ROwrR11IddKAM08vohxA==} request@2.88.2: - resolution: - { - integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==, - } - engines: { node: '>= 6' } + resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} + engines: {node: '>= 6'} deprecated: request has been deprecated, see https://github.com/request/request/issues/3142 require-directory@2.1.1: - resolution: - { - integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} require-from-string@2.0.2: - resolution: - { - integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} require-main-filename@2.0.0: - resolution: - { - integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==, - } + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} resolve-cwd@3.0.0: - resolution: - { - integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} resolve-from@4.0.0: - resolution: - { - integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} resolve-from@5.0.0: - resolution: - { - integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} resolve-pkg-maps@1.0.0: - resolution: - { - integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==, - } + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} resolve.exports@2.0.3: - resolution: - { - integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} + engines: {node: '>=10'} resolve@1.22.11: - resolution: - { - integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} hasBin: true restore-cursor@3.1.0: - resolution: - { - integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} retry@0.12.0: - resolution: - { - integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==, - } - engines: { node: '>= 4' } + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} reusify@1.1.0: - resolution: - { - integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==, - } - engines: { iojs: '>=1.0.0', node: '>=0.10.0' } + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} rimraf@3.0.2: - resolution: - { - integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==, - } + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@4.4.1: - resolution: - { - integrity: sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==} + engines: {node: '>=14'} hasBin: true rimraf@6.1.2: - resolution: - { - integrity: sha512-cFCkPslJv7BAXJsYlK1dZsbP8/ZNLkCAQ0bi1hf5EKX2QHegmDFEFA6QhuYJlk7UDdc+02JjO80YSOrWPpw06g==, - } - engines: { node: 20 || >=22 } + resolution: {integrity: sha512-cFCkPslJv7BAXJsYlK1dZsbP8/ZNLkCAQ0bi1hf5EKX2QHegmDFEFA6QhuYJlk7UDdc+02JjO80YSOrWPpw06g==} + engines: {node: 20 || >=22} + hasBin: true + + rollup-plugin-visualizer@6.0.5: + resolution: {integrity: sha512-9+HlNgKCVbJDs8tVtjQ43US12eqaiHyyiLMdBwQ7vSZPiHMysGNo2E88TAp1si5wx8NAoYriI2A5kuKfIakmJg==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + rolldown: 1.x || ^1.0.0-beta + rollup: 2.x || 3.x || 4.x + peerDependenciesMeta: + rolldown: + optional: true + rollup: + optional: true + + rollup@4.57.1: + resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==} + 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' } + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} run-async@2.4.1: - resolution: - { - integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==, - } - engines: { node: '>=0.12.0' } + resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} + engines: {node: '>=0.12.0'} run-parallel@1.2.0: - resolution: - { - integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==, - } + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} rxjs@7.8.2: - resolution: - { - integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==, - } + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} safe-buffer@5.1.2: - resolution: - { - integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==, - } + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} safe-buffer@5.2.1: - resolution: - { - integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==, - } + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} safer-buffer@2.1.2: - resolution: - { - integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==, - } + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} scheduler@0.27.0: - resolution: - { - integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==, - } + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} semver@5.7.2: - resolution: - { - integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==, - } + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true semver@6.3.1: - resolution: - { - integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, - } + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true semver@7.7.3: - resolution: - { - integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} hasBin: true send@1.2.1: - resolution: - { - integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==, - } - engines: { node: '>= 18' } + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} serve-static@2.2.1: - resolution: - { - integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==, - } - engines: { node: '>= 18' } + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} set-blocking@2.0.0: - resolution: - { - integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==, - } + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} set-function-length@1.2.2: - resolution: - { - integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} setprototypeof@1.1.1: - resolution: - { - integrity: sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==, - } + resolution: {integrity: sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==} setprototypeof@1.2.0: - resolution: - { - integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==, - } + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} shallow-clone@3.0.1: - resolution: - { - integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} + engines: {node: '>=8'} shallowequal@1.1.0: - resolution: - { - integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==, - } + resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} shebang-command@2.0.0: - resolution: - { - integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} shebang-regex@3.0.0: - resolution: - { - integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} shelljs@0.10.0: - resolution: - { - integrity: sha512-Jex+xw5Mg2qMZL3qnzXIfaxEtBaC4n7xifqaqtrZDdlheR70OGkydrPJWT0V1cA1k3nanC86x9FwAmQl6w3Klw==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-Jex+xw5Mg2qMZL3qnzXIfaxEtBaC4n7xifqaqtrZDdlheR70OGkydrPJWT0V1cA1k3nanC86x9FwAmQl6w3Klw==} + engines: {node: '>=18'} side-channel-list@1.0.0: - resolution: - { - integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} side-channel-map@1.0.1: - resolution: - { - integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==, - } - engines: { node: '>= 0.4' } + 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' } + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} side-channel@1.1.0: - resolution: - { - integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} signal-exit@3.0.7: - resolution: - { - integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==, - } + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} signal-exit@4.1.0: - resolution: - { - integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==, - } - engines: { node: '>=14' } + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} sigstore@2.3.1: - resolution: - { - integrity: sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==} + engines: {node: ^16.14.0 || >=18.0.0} simple-update-notifier@2.0.0: - resolution: - { - integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} + engines: {node: '>=10'} slash@3.0.0: - resolution: - { - integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} slick@1.12.2: - resolution: - { - integrity: sha512-4qdtOGcBjral6YIBCWJ0ljFSKNLz9KkhbWtuGvUyRowl1kxfuE1x/Z/aJcaiilpb3do9bl5K7/1h9XC5wWpY/A==, - } + resolution: {integrity: sha512-4qdtOGcBjral6YIBCWJ0ljFSKNLz9KkhbWtuGvUyRowl1kxfuE1x/Z/aJcaiilpb3do9bl5K7/1h9XC5wWpY/A==} smart-buffer@4.2.0: - resolution: - { - integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==, - } - engines: { node: '>= 6.0.0', npm: '>= 3.0.0' } + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} smtp-server@3.18.0: - resolution: - { - integrity: sha512-xINTnh0H8JDAKOAGSnFX8mgXB/L4Oz8dG4P0EgKAzJEszngxEEx4vOys+yNpsUc6yIyTKS8m2BcIffq4Htma/w==, - } - engines: { node: '>=18.18.0' } + resolution: {integrity: sha512-xINTnh0H8JDAKOAGSnFX8mgXB/L4Oz8dG4P0EgKAzJEszngxEEx4vOys+yNpsUc6yIyTKS8m2BcIffq4Htma/w==} + engines: {node: '>=18.18.0'} socks-proxy-agent@8.0.5: - resolution: - { - integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==, - } - engines: { node: '>= 14' } + resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} + engines: {node: '>= 14'} socks@2.8.7: - resolution: - { - integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==, - } - engines: { node: '>= 10.0.0', npm: '>= 3.0.0' } + resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} sort-keys@2.0.0: - resolution: - { - integrity: sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg==} + engines: {node: '>=4'} sorted-array-functions@1.3.0: - resolution: - { - integrity: sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==, - } + resolution: {integrity: sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} source-map-resolve@0.6.0: - resolution: - { - integrity: sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==, - } + resolution: {integrity: sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==} deprecated: See https://github.com/lydell/source-map-resolve#deprecated source-map-support@0.5.13: - resolution: - { - integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==, - } + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} source-map@0.6.1: - resolution: - { - integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} spdx-correct@3.2.0: - resolution: - { - integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==, - } + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} spdx-exceptions@2.5.0: - resolution: - { - integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==, - } + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} spdx-expression-parse@3.0.1: - resolution: - { - integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==, - } + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} spdx-license-ids@3.0.22: - resolution: - { - integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==, - } + resolution: {integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==} split2@3.2.2: - resolution: - { - integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==, - } + resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} split2@4.2.0: - resolution: - { - integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==, - } - engines: { node: '>= 10.x' } + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} split@1.0.1: - resolution: - { - integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==, - } + resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} sprintf-js@1.0.3: - resolution: - { - integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==, - } + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} sshpk@1.18.0: - resolution: - { - integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} + engines: {node: '>=0.10.0'} hasBin: true ssri@10.0.6: - resolution: - { - integrity: sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} stack-utils@2.0.6: - resolution: - { - integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} statuses@1.5.0: - resolution: - { - integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==, - } - engines: { node: '>= 0.6' } + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} statuses@2.0.2: - resolution: - { - integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==, - } - engines: { node: '>= 0.8' } + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} stream-browserify@3.0.0: - resolution: - { - integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==, - } + resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} streamsearch@0.1.2: - resolution: - { - integrity: sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA==, - } - engines: { node: '>=0.8.0' } + resolution: {integrity: sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA==} + engines: {node: '>=0.8.0'} strfy-js@3.1.10: - resolution: - { - integrity: sha512-KQXNrvhnWpn4ya25WSG6EvJC6oqdeXlwMoitGl3qEJ2wnELV/sQO6uBy6CsIWTsVOMAt0B7/xvM40ucu5c8AuA==, - } + resolution: {integrity: sha512-KQXNrvhnWpn4ya25WSG6EvJC6oqdeXlwMoitGl3qEJ2wnELV/sQO6uBy6CsIWTsVOMAt0B7/xvM40ucu5c8AuA==} string-length@4.0.2: - resolution: - { - integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} string-width@4.2.3: - resolution: - { - integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==, - } - engines: { node: '>=8' } + 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' } + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} string_decoder@0.10.31: - resolution: - { - integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==, - } + resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} string_decoder@1.1.1: - resolution: - { - integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==, - } + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} string_decoder@1.3.0: - resolution: - { - integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==, - } + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} strip-ansi@6.0.1: - resolution: - { - integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} strip-ansi@7.1.2: - resolution: - { - integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==, - } - engines: { node: '>=12' } + resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + engines: {node: '>=12'} strip-bom@3.0.0: - resolution: - { - integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} strip-bom@4.0.0: - resolution: - { - integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} strip-final-newline@2.0.0: - resolution: - { - integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} strip-indent@3.0.0: - resolution: - { - integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} strip-json-comments@3.1.1: - resolution: - { - integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} strnum@2.1.2: - resolution: - { - integrity: sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==, - } + resolution: {integrity: sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==} styled-components@5.3.11: - resolution: - { - integrity: sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==} + engines: {node: '>=10'} peerDependencies: react: '>= 16.8.0' react-dom: '>= 16.8.0' react-is: '>= 16.8.0' styled-system@5.1.5: - resolution: - { - integrity: sha512-7VoD0o2R3RKzOzPK0jYrVnS8iJdfkKsQJNiLRDjikOpQVqQHns/DXWaPZOH4tIKkhAT7I6wIsy9FWTWh2X3q+A==, - } + resolution: {integrity: sha512-7VoD0o2R3RKzOzPK0jYrVnS8iJdfkKsQJNiLRDjikOpQVqQHns/DXWaPZOH4tIKkhAT7I6wIsy9FWTWh2X3q+A==} subscriptions-transport-ws@0.9.19: - resolution: - { - integrity: sha512-dxdemxFFB0ppCLg10FTtRqH/31FNRL1y1BQv8209MK5I4CwALb7iihQg+7p65lFcIl8MHatINWBLOqpgU4Kyyw==, - } + resolution: {integrity: sha512-dxdemxFFB0ppCLg10FTtRqH/31FNRL1y1BQv8209MK5I4CwALb7iihQg+7p65lFcIl8MHatINWBLOqpgU4Kyyw==} deprecated: The `subscriptions-transport-ws` package is no longer maintained. We recommend you use `graphql-ws` instead. For help migrating Apollo software to `graphql-ws`, see https://www.apollographql.com/docs/apollo-server/data/subscriptions/#switching-from-subscriptions-transport-ws For general help using `graphql-ws`, see https://github.com/enisdenjo/graphql-ws/blob/master/README.md peerDependencies: graphql: '>=0.10.0' superagent@10.3.0: - resolution: - { - integrity: sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ==, - } - engines: { node: '>=14.18.0' } + resolution: {integrity: sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ==} + engines: {node: '>=14.18.0'} supertest@7.2.2: - resolution: - { - integrity: sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==, - } - engines: { node: '>=14.18.0' } + resolution: {integrity: sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==} + engines: {node: '>=14.18.0'} supports-color@5.5.0: - resolution: - { - integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} supports-color@7.2.0: - resolution: - { - integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} supports-color@8.1.1: - resolution: - { - integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} supports-preserve-symlinks-flag@1.0.0: - resolution: - { - integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==, - } - engines: { node: '>= 0.4' } + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} symbol-observable@1.2.0: - resolution: - { - integrity: sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==} + engines: {node: '>=0.10.0'} synckit@0.11.12: - resolution: - { - integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==, - } - engines: { node: ^14.18.0 || >=16.0.0 } + resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} + engines: {node: ^14.18.0 || >=16.0.0} tar-stream@2.2.0: - resolution: - { - integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} tar@6.2.1: - resolution: - { - integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==, - } - engines: { node: '>=10' } - deprecated: Old versions of tar 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 exhorbitant rates) by contacting i@izs.me + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + engines: {node: '>=10'} + deprecated: Old versions of tar 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 temp-dir@1.0.0: - resolution: - { - integrity: sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ==} + engines: {node: '>=4'} test-exclude@6.0.0: - resolution: - { - integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} text-extensions@1.9.0: - resolution: - { - integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==, - } - engines: { node: '>=0.10' } + resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==} + engines: {node: '>=0.10'} through2@2.0.5: - resolution: - { - integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==, - } + resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} through2@3.0.2: - resolution: - { - integrity: sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==, - } + resolution: {integrity: sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==} through@2.3.8: - resolution: - { - integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==, - } + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} tinyglobby@0.2.12: - resolution: - { - integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==, - } - engines: { node: '>=12.0.0' } + resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==} + engines: {node: '>=12.0.0'} tinyglobby@0.2.15: - resolution: - { - integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==, - } - engines: { node: '>=12.0.0' } + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} tinypool@2.0.0: - resolution: - { - integrity: sha512-/RX9RzeH2xU5ADE7n2Ykvmi9ED3FBGPAjw9u3zucrNNaEBIO0HPSYgL0NT7+3p147ojeSdaVu08F6hjpv31HJg==, - } - engines: { node: ^20.0.0 || >=22.0.0 } + resolution: {integrity: sha512-/RX9RzeH2xU5ADE7n2Ykvmi9ED3FBGPAjw9u3zucrNNaEBIO0HPSYgL0NT7+3p147ojeSdaVu08F6hjpv31HJg==} + engines: {node: ^20.0.0 || >=22.0.0} tmp@0.2.5: - resolution: - { - integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==, - } - engines: { node: '>=14.14' } + resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} + engines: {node: '>=14.14'} tmpl@1.0.5: - resolution: - { - integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==, - } + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} to-regex-range@5.0.1: - resolution: - { - integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, - } - engines: { node: '>=8.0' } + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} toidentifier@1.0.0: - resolution: - { - integrity: sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==, - } - engines: { node: '>=0.6' } + resolution: {integrity: sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==} + engines: {node: '>=0.6'} toidentifier@1.0.1: - resolution: - { - integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==, - } - engines: { node: '>=0.6' } + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} touch@3.1.1: - resolution: - { - integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==, - } + resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==} hasBin: true tough-cookie@2.5.0: - resolution: - { - integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==, - } - engines: { node: '>=0.8' } + resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==} + engines: {node: '>=0.8'} tr46@0.0.3: - resolution: - { - integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==, - } + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} treeverse@3.0.0: - resolution: - { - integrity: sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} trim-newlines@3.0.1: - resolution: - { - integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} + engines: {node: '>=8'} ts-api-utils@2.4.0: - resolution: - { - integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==, - } - engines: { node: '>=18.12' } + resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} + engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' ts-jest@29.4.6: - resolution: - { - integrity: sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==, - } - engines: { node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0 } + resolution: {integrity: sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==} + engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: '@babel/core': '>=7.0.0-beta.0 <8' @@ -12502,10 +8676,7 @@ packages: optional: true ts-node@10.9.2: - resolution: - { - integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==, - } + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true peerDependencies: '@swc/core': '>=1.2.50' @@ -12519,491 +8690,315 @@ packages: optional: true tsconfig-paths@4.2.0: - resolution: - { - integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} + engines: {node: '>=6'} tslib@2.8.1: - resolution: - { - integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==, - } + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} tsx@4.21.0: - resolution: - { - integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==, - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} hasBin: true tuf-js@2.2.1: - resolution: - { - integrity: sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==, - } - engines: { node: ^16.14.0 || >=18.0.0 } + resolution: {integrity: sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==} + engines: {node: ^16.14.0 || >=18.0.0} tunnel-agent@0.6.0: - resolution: - { - integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==, - } + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} tweetnacl@0.14.5: - resolution: - { - integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==, - } + resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} type-check@0.4.0: - resolution: - { - integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==, - } - engines: { node: '>= 0.8.0' } + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} type-detect@4.0.8: - resolution: - { - integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} type-fest@0.18.1: - resolution: - { - integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==} + engines: {node: '>=10'} type-fest@0.21.3: - resolution: - { - integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} type-fest@0.4.1: - resolution: - { - integrity: sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==} + engines: {node: '>=6'} type-fest@0.6.0: - resolution: - { - integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} + engines: {node: '>=8'} type-fest@0.8.1: - resolution: - { - integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} type-fest@4.41.0: - resolution: - { - integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==, - } - engines: { node: '>=16' } + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} type-is@1.6.18: - resolution: - { - integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==, - } - engines: { node: '>= 0.6' } + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} type-is@2.0.1: - resolution: - { - integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==, - } - engines: { node: '>= 0.6' } + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} typedarray@0.0.6: - resolution: - { - integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==, - } + resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} typescript@5.9.3: - resolution: - { - integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==, - } - engines: { node: '>=14.17' } + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} hasBin: true uglify-js@3.19.3: - resolution: - { - integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==, - } - engines: { node: '>=0.8.0' } + resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} + engines: {node: '>=0.8.0'} hasBin: true uglify-js@3.4.10: - resolution: - { - integrity: sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==, - } - engines: { node: '>=0.8.0' } + resolution: {integrity: sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==} + engines: {node: '>=0.8.0'} hasBin: true undefsafe@2.0.5: - resolution: - { - integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==, - } + resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} undici-types@5.26.5: - resolution: - { - integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==, - } + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} undici-types@6.21.0: - resolution: - { - integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==, - } + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} undici@7.16.0: - resolution: - { - integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==, - } - engines: { node: '>=20.18.1' } + resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==} + engines: {node: '>=20.18.1'} undici@7.19.0: - resolution: - { - integrity: sha512-Heho1hJD81YChi+uS2RkSjcVO+EQLmLSyUlHyp7Y/wFbxQaGb4WXVKD073JytrjXJVkSZVzoE2MCSOKugFGtOQ==, - } - engines: { node: '>=20.18.1' } + resolution: {integrity: sha512-Heho1hJD81YChi+uS2RkSjcVO+EQLmLSyUlHyp7Y/wFbxQaGb4WXVKD073JytrjXJVkSZVzoE2MCSOKugFGtOQ==} + engines: {node: '>=20.18.1'} unique-filename@3.0.0: - resolution: - { - integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} unique-slug@4.0.0: - resolution: - { - integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} universal-user-agent@6.0.1: - resolution: - { - integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==, - } + resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==} universalify@2.0.1: - resolution: - { - integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==, - } - engines: { node: '>= 10.0.0' } + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} unload@2.2.0: - resolution: - { - integrity: sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==, - } + resolution: {integrity: sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==} unpipe@1.0.0: - resolution: - { - integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==, - } - engines: { node: '>= 0.8' } + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} unrs-resolver@1.11.1: - resolution: - { - integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==, - } + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} untildify@4.0.0: - resolution: - { - integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} + engines: {node: '>=8'} upath@2.0.1: - resolution: - { - integrity: sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==, - } - engines: { node: '>=4' } + resolution: {integrity: sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==} + engines: {node: '>=4'} update-browserslist-db@1.2.3: - resolution: - { - integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==, - } + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' upper-case@1.1.3: - resolution: - { - integrity: sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==, - } + resolution: {integrity: sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==} uri-js@4.4.1: - resolution: - { - integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, - } + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} url-join@4.0.1: - resolution: - { - integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==, - } + resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} util-deprecate@1.0.2: - resolution: - { - integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, - } + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} uuid@10.0.0: - resolution: - { - integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==, - } + resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} hasBin: true uuid@3.4.0: - resolution: - { - integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==, - } + resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. hasBin: true v8-compile-cache-lib@3.0.1: - resolution: - { - integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==, - } + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} v8-to-istanbul@9.3.0: - resolution: - { - integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==, - } - engines: { node: '>=10.12.0' } + resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} + engines: {node: '>=10.12.0'} valid-data-url@3.0.1: - resolution: - { - integrity: sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==} + engines: {node: '>=10'} validate-npm-package-license@3.0.4: - resolution: - { - integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==, - } + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} validate-npm-package-name@5.0.1: - resolution: - { - integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} vary@1.1.2: - resolution: - { - integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==, - } - engines: { node: '>= 0.8' } + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} verror@1.10.0: - resolution: - { - integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==, - } - engines: { '0': node >=0.6.0 } + resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} + engines: {'0': node >=0.6.0} + + vite@6.4.1: + resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true walk-up-path@3.0.1: - resolution: - { - integrity: sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==, - } + resolution: {integrity: sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==} walker@1.0.8: - resolution: - { - integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==, - } + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} warning@3.0.0: - resolution: - { - integrity: sha512-jMBt6pUrKn5I+OGgtQ4YZLdhIeJmObddh6CsibPxyQ5yPZm1XExSyzC1LCNX7BzhxWgiHmizBWJTHJIjMjTQYQ==, - } + resolution: {integrity: sha512-jMBt6pUrKn5I+OGgtQ4YZLdhIeJmObddh6CsibPxyQ5yPZm1XExSyzC1LCNX7BzhxWgiHmizBWJTHJIjMjTQYQ==} wcwidth@1.0.1: - resolution: - { - integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==, - } + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} web-resource-inliner@5.0.0: - resolution: - { - integrity: sha512-AIihwH+ZmdHfkJm7BjSXiEClVt4zUFqX4YlFAzjL13wLtDuUneSaFvDBTbdYRecs35SiU7iNKbMnN+++wVfb6A==, - } - engines: { node: '>=10.0.0' } + resolution: {integrity: sha512-AIihwH+ZmdHfkJm7BjSXiEClVt4zUFqX4YlFAzjL13wLtDuUneSaFvDBTbdYRecs35SiU7iNKbMnN+++wVfb6A==} + engines: {node: '>=10.0.0'} webidl-conversions@3.0.1: - resolution: - { - integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==, - } + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} whatwg-encoding@3.1.1: - resolution: - { - integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-mimetype@4.0.0: - resolution: - { - integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==, - } - engines: { node: '>=18' } + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} whatwg-url@5.0.0: - resolution: - { - integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==, - } + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} which-module@2.0.1: - resolution: - { - integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==, - } + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} which@2.0.2: - resolution: - { - integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, - } - engines: { node: '>= 8' } + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} hasBin: true which@4.0.0: - resolution: - { - integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==, - } - engines: { node: ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} + engines: {node: ^16.13.0 || >=18.0.0} hasBin: true wide-align@1.1.5: - resolution: - { - integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==, - } + resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} word-wrap@1.2.5: - resolution: - { - integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==, - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} wordwrap@1.0.0: - resolution: - { - integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==, - } + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} wrap-ansi@6.2.0: - resolution: - { - integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==, - } - engines: { node: '>=8' } + 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' } + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} wrap-ansi@8.1.0: - resolution: - { - integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==, - } - engines: { node: '>=12' } + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} wrappy@1.0.2: - resolution: - { - integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, - } + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} write-file-atomic@2.4.3: - resolution: - { - integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==, - } + resolution: {integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==} write-file-atomic@5.0.1: - resolution: - { - integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} write-json-file@3.2.0: - resolution: - { - integrity: sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ==} + engines: {node: '>=6'} write-pkg@4.0.0: - resolution: - { - integrity: sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA==} + engines: {node: '>=8'} ws@7.5.10: - resolution: - { - integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==, - } - engines: { node: '>=8.3.0' } + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} + engines: {node: '>=8.3.0'} peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ^5.0.2 @@ -13014,114 +9009,67 @@ packages: optional: true xtend@4.0.2: - resolution: - { - integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==, - } - engines: { node: '>=0.4' } + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} y18n@4.0.3: - resolution: - { - integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==, - } + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} y18n@5.0.8: - resolution: - { - integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} yallist@2.1.2: - resolution: - { - integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==, - } + resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} yallist@3.1.1: - resolution: - { - integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==, - } + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} yallist@4.0.0: - resolution: - { - integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==, - } + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} yaml@2.8.2: - resolution: - { - integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==, - } - engines: { node: '>= 14.6' } + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + engines: {node: '>= 14.6'} hasBin: true yanse@0.2.0: - resolution: - { - integrity: sha512-BN6WYjJRX3mw/LpEC4d2LAlLFFdoFKKYYbd9nvhTvbbEW+/mJJccBGy0DuvcYXg75Xed2ZT8euXtplfLKBfdHA==, - } + resolution: {integrity: sha512-BN6WYjJRX3mw/LpEC4d2LAlLFFdoFKKYYbd9nvhTvbbEW+/mJJccBGy0DuvcYXg75Xed2ZT8euXtplfLKBfdHA==} yargs-parser@18.1.3: - resolution: - { - integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} yargs-parser@20.2.9: - resolution: - { - integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} yargs-parser@21.1.1: - resolution: - { - integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==, - } - engines: { node: '>=12' } + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} yargs@15.4.1: - resolution: - { - integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==, - } - engines: { node: '>=8' } + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} yargs@16.2.0: - resolution: - { - integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} yargs@17.7.2: - resolution: - { - integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==, - } - engines: { node: '>=12' } + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} yn@3.1.1: - resolution: - { - integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==, - } - engines: { node: '>=6' } + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} yocto-queue@0.1.0: - resolution: - { - integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, - } - engines: { node: '>=10' } + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} snapshots: + '@0no-co/graphql.web@1.2.0(graphql@15.10.1)': optionalDependencies: graphql: 15.10.1 @@ -14125,6 +10073,16 @@ snapshots: '@babel/core': 7.28.6 '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.6)': + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.6)': + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/runtime-corejs3@7.28.4': dependencies: core-js-pure: 3.47.0 @@ -14217,81 +10175,159 @@ snapshots: '@emotion/unitless@0.7.5': {} + '@esbuild/aix-ppc64@0.25.12': + optional: true + '@esbuild/aix-ppc64@0.27.2': optional: true + '@esbuild/android-arm64@0.25.12': + optional: true + '@esbuild/android-arm64@0.27.2': optional: true + '@esbuild/android-arm@0.25.12': + optional: true + '@esbuild/android-arm@0.27.2': optional: true + '@esbuild/android-x64@0.25.12': + optional: true + '@esbuild/android-x64@0.27.2': optional: true + '@esbuild/darwin-arm64@0.25.12': + optional: true + '@esbuild/darwin-arm64@0.27.2': optional: true + '@esbuild/darwin-x64@0.25.12': + optional: true + '@esbuild/darwin-x64@0.27.2': optional: true + '@esbuild/freebsd-arm64@0.25.12': + optional: true + '@esbuild/freebsd-arm64@0.27.2': optional: true + '@esbuild/freebsd-x64@0.25.12': + optional: true + '@esbuild/freebsd-x64@0.27.2': optional: true + '@esbuild/linux-arm64@0.25.12': + optional: true + '@esbuild/linux-arm64@0.27.2': optional: true + '@esbuild/linux-arm@0.25.12': + optional: true + '@esbuild/linux-arm@0.27.2': optional: true + '@esbuild/linux-ia32@0.25.12': + optional: true + '@esbuild/linux-ia32@0.27.2': optional: true + '@esbuild/linux-loong64@0.25.12': + optional: true + '@esbuild/linux-loong64@0.27.2': optional: true + '@esbuild/linux-mips64el@0.25.12': + optional: true + '@esbuild/linux-mips64el@0.27.2': optional: true + '@esbuild/linux-ppc64@0.25.12': + optional: true + '@esbuild/linux-ppc64@0.27.2': optional: true + '@esbuild/linux-riscv64@0.25.12': + optional: true + '@esbuild/linux-riscv64@0.27.2': optional: true + '@esbuild/linux-s390x@0.25.12': + optional: true + '@esbuild/linux-s390x@0.27.2': optional: true + '@esbuild/linux-x64@0.25.12': + optional: true + '@esbuild/linux-x64@0.27.2': optional: true + '@esbuild/netbsd-arm64@0.25.12': + optional: true + '@esbuild/netbsd-arm64@0.27.2': optional: true + '@esbuild/netbsd-x64@0.25.12': + optional: true + '@esbuild/netbsd-x64@0.27.2': optional: true + '@esbuild/openbsd-arm64@0.25.12': + optional: true + '@esbuild/openbsd-arm64@0.27.2': optional: true + '@esbuild/openbsd-x64@0.25.12': + optional: true + '@esbuild/openbsd-x64@0.27.2': optional: true + '@esbuild/openharmony-arm64@0.25.12': + optional: true + '@esbuild/openharmony-arm64@0.27.2': optional: true + '@esbuild/sunos-x64@0.25.12': + optional: true + '@esbuild/sunos-x64@0.27.2': optional: true + '@esbuild/win32-arm64@0.25.12': + optional: true + '@esbuild/win32-arm64@0.27.2': optional: true + '@esbuild/win32-ia32@0.25.12': + optional: true + '@esbuild/win32-ia32@0.27.2': optional: true + '@esbuild/win32-x64@0.25.12': + optional: true + '@esbuild/win32-x64@0.27.2': optional: true @@ -14396,6 +10432,10 @@ snapshots: dependencies: '@isaacs/balanced-match': 4.0.1 + '@isaacs/brace-expansion@5.0.1': + dependencies: + '@isaacs/balanced-match': 4.0.1 + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -14405,6 +10445,8 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/cliui@9.0.0': {} + '@isaacs/string-locale-compare@1.1.0': {} '@istanbuljs/load-nyc-config@1.1.0': @@ -14632,14 +10674,14 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@launchql/mjml@0.1.1(@babel/core@7.28.6)(encoding@0.1.13)(react-dom@19.2.3(react@19.2.3))(react-is@18.3.1)(react@19.2.3)': + '@launchql/mjml@0.1.1(@babel/core@7.28.6)(encoding@0.1.13)(react-dom@19.2.3(react@19.2.3))(react-is@19.2.4)(react@19.2.3)': dependencies: '@babel/runtime': 7.28.4 mjml: 4.7.1(encoding@0.1.13) mjml-react: 1.0.59(mjml@4.7.1(encoding@0.1.13))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - styled-components: 5.3.11(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react-is@18.3.1)(react@19.2.3) + styled-components: 5.3.11(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react-is@19.2.4)(react@19.2.3) styled-system: 5.1.5 transitivePeerDependencies: - '@babel/core' @@ -14661,13 +10703,13 @@ snapshots: '@types/node': 20.19.27 long: 5.3.2 - '@launchql/styled-email@0.1.0(@babel/core@7.28.6)(encoding@0.1.13)(react-dom@19.2.3(react@19.2.3))(react-is@18.3.1)(react@19.2.3)': + '@launchql/styled-email@0.1.0(@babel/core@7.28.6)(encoding@0.1.13)(react-dom@19.2.3(react@19.2.3))(react-is@19.2.4)(react@19.2.3)': dependencies: '@babel/runtime': 7.28.4 juice: 7.0.0(encoding@0.1.13) react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - styled-components: 5.3.11(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react-is@18.3.1)(react@19.2.3) + styled-components: 5.3.11(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react-is@19.2.4)(react@19.2.3) styled-system: 5.1.5 transitivePeerDependencies: - '@babel/core' @@ -15121,6 +11163,83 @@ snapshots: '@protobufjs/utf8@1.1.0': {} + '@rolldown/pluginutils@1.0.0-beta.27': {} + + '@rollup/rollup-android-arm-eabi@4.57.1': + optional: true + + '@rollup/rollup-android-arm64@4.57.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.57.1': + optional: true + + '@rollup/rollup-darwin-x64@4.57.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.57.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.57.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.57.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.57.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.57.1': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.57.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.57.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.57.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.57.1': + optional: true + + '@rollup/rollup-openbsd-x64@4.57.1': + optional: true + + '@rollup/rollup-openharmony-arm64@4.57.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.57.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.57.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.57.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.57.1': + optional: true + '@sigstore/bundle@2.3.2': dependencies: '@sigstore/protobuf-specs': 0.3.3 @@ -15744,11 +11863,18 @@ snapshots: '@tanstack/query-core@5.90.19': {} + '@tanstack/query-core@5.90.20': {} + '@tanstack/react-query@5.90.19(react@19.2.3)': dependencies: '@tanstack/query-core': 5.90.19 react: 19.2.3 + '@tanstack/react-query@5.90.20(react@19.2.3)': + dependencies: + '@tanstack/query-core': 5.90.20 + react: 19.2.3 + '@testing-library/dom@7.31.2': dependencies: '@babel/code-frame': 7.27.1 @@ -15971,6 +12097,14 @@ snapshots: '@types/range-parser@1.2.7': {} + '@types/react-dom@19.2.3(@types/react@19.2.13)': + dependencies: + '@types/react': 19.2.13 + + '@types/react@19.2.13': + dependencies: + csstype: 3.2.3 + '@types/react@19.2.8': dependencies: csstype: 3.2.3 @@ -16186,6 +12320,18 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true + '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@20.19.27)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))': + dependencies: + '@babel/core': 7.28.6 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.6) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.6) + '@rolldown/pluginutils': 1.0.0-beta.27 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 6.4.1(@types/node@20.19.27)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + transitivePeerDependencies: + - supports-color + '@yarnpkg/lockfile@1.1.0': {} '@yarnpkg/parsers@3.0.2': @@ -16362,14 +12508,14 @@ snapshots: dependencies: '@types/babel__core': 7.20.5 - babel-plugin-styled-components@2.1.4(@babel/core@7.28.6)(styled-components@5.3.11(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react-is@18.3.1)(react@19.2.3))(supports-color@5.5.0): + babel-plugin-styled-components@2.1.4(@babel/core@7.28.6)(styled-components@5.3.11(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react-is@19.2.4)(react@19.2.3))(supports-color@5.5.0): dependencies: '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-module-imports': 7.27.1(supports-color@5.5.0) '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.6) lodash: 4.17.21 picomatch: 2.3.1 - styled-components: 5.3.11(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react-is@18.3.1)(react@19.2.3) + styled-components: 5.3.11(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react-is@19.2.4)(react@19.2.3) transitivePeerDependencies: - '@babel/core' - supports-color @@ -17191,6 +13337,35 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + esbuild@0.27.2: optionalDependencies: '@esbuild/aix-ppc64': 0.27.2 @@ -17662,8 +13837,8 @@ snapshots: glob@11.1.0: dependencies: foreground-child: 3.3.1 - jackspeak: 4.1.1 - minimatch: 10.1.1 + jackspeak: 4.2.3 + minimatch: 10.1.2 minipass: 7.1.2 package-json-from-dist: 1.0.1 path-scurry: 2.0.1 @@ -18141,9 +14316,9 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jackspeak@4.1.1: + jackspeak@4.2.3: dependencies: - '@isaacs/cliui': 8.0.2 + '@isaacs/cliui': 9.0.0 jake@10.9.4: dependencies: @@ -18809,7 +14984,7 @@ snapshots: transitivePeerDependencies: - debug - makage@0.1.10: + makage@0.1.12: dependencies: glob: 11.1.0 yaml: 2.8.2 @@ -18914,6 +15089,10 @@ snapshots: dependencies: '@isaacs/brace-expansion': 5.0.0 + minimatch@10.1.2: + dependencies: + '@isaacs/brace-expansion': 5.0.1 + minimatch@3.0.5: dependencies: brace-expansion: 1.1.12 @@ -19314,6 +15493,8 @@ snapshots: dependencies: big-integer: 1.6.52 + nanoid@3.3.11: {} + napi-postinstall@0.3.4: {} natural-compare@1.4.0: {} @@ -19702,7 +15883,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.27.1 + '@babel/code-frame': 7.28.6 error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -19878,6 +16059,12 @@ snapshots: postcss-value-parser@4.2.0: {} + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + postgraphile-core@4.14.1(graphql@15.10.1)(pg@8.17.1): dependencies: graphile-build: 4.14.1(graphql@15.10.1) @@ -20045,6 +16232,8 @@ snapshots: react-is@18.3.1: {} + react-is@19.2.4: {} + react-query@3.39.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: '@babel/runtime': 7.28.4 @@ -20054,6 +16243,14 @@ snapshots: optionalDependencies: react-dom: 19.2.3(react@19.2.3) + react-refresh@0.17.0: {} + + react-test-renderer@19.2.3(react@19.2.3): + dependencies: + react: 19.2.3 + react-is: 19.2.4 + scheduler: 0.27.0 + react@19.2.3: {} read-cmd-shim@4.0.0: {} @@ -20200,6 +16397,46 @@ snapshots: glob: 13.0.0 package-json-from-dist: 1.0.1 + rollup-plugin-visualizer@6.0.5(rollup@4.57.1): + dependencies: + open: 8.4.2 + picomatch: 4.0.3 + source-map: 0.7.6 + yargs: 17.7.2 + optionalDependencies: + rollup: 4.57.1 + + rollup@4.57.1: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.57.1 + '@rollup/rollup-android-arm64': 4.57.1 + '@rollup/rollup-darwin-arm64': 4.57.1 + '@rollup/rollup-darwin-x64': 4.57.1 + '@rollup/rollup-freebsd-arm64': 4.57.1 + '@rollup/rollup-freebsd-x64': 4.57.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.57.1 + '@rollup/rollup-linux-arm-musleabihf': 4.57.1 + '@rollup/rollup-linux-arm64-gnu': 4.57.1 + '@rollup/rollup-linux-arm64-musl': 4.57.1 + '@rollup/rollup-linux-loong64-gnu': 4.57.1 + '@rollup/rollup-linux-loong64-musl': 4.57.1 + '@rollup/rollup-linux-ppc64-gnu': 4.57.1 + '@rollup/rollup-linux-ppc64-musl': 4.57.1 + '@rollup/rollup-linux-riscv64-gnu': 4.57.1 + '@rollup/rollup-linux-riscv64-musl': 4.57.1 + '@rollup/rollup-linux-s390x-gnu': 4.57.1 + '@rollup/rollup-linux-x64-gnu': 4.57.1 + '@rollup/rollup-linux-x64-musl': 4.57.1 + '@rollup/rollup-openbsd-x64': 4.57.1 + '@rollup/rollup-openharmony-arm64': 4.57.1 + '@rollup/rollup-win32-arm64-msvc': 4.57.1 + '@rollup/rollup-win32-ia32-msvc': 4.57.1 + '@rollup/rollup-win32-x64-gnu': 4.57.1 + '@rollup/rollup-win32-x64-msvc': 4.57.1 + fsevents: 2.3.3 + router@2.2.0: dependencies: debug: 4.4.3(supports-color@5.5.0) @@ -20370,6 +16607,8 @@ snapshots: sorted-array-functions@1.3.0: {} + source-map-js@1.2.1: {} + source-map-resolve@0.6.0: dependencies: atob: 2.1.2 @@ -20382,6 +16621,8 @@ snapshots: source-map@0.6.1: {} + source-map@0.7.6: {} + spdx-correct@3.2.0: dependencies: spdx-expression-parse: 3.0.1 @@ -20492,19 +16733,19 @@ snapshots: strnum@2.1.2: {} - styled-components@5.3.11(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react-is@18.3.1)(react@19.2.3): + styled-components@5.3.11(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react-is@19.2.4)(react@19.2.3): dependencies: '@babel/helper-module-imports': 7.27.1(supports-color@5.5.0) '@babel/traverse': 7.28.6(supports-color@5.5.0) '@emotion/is-prop-valid': 1.4.0 '@emotion/stylis': 0.8.5 '@emotion/unitless': 0.7.5 - babel-plugin-styled-components: 2.1.4(@babel/core@7.28.6)(styled-components@5.3.11(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react-is@18.3.1)(react@19.2.3))(supports-color@5.5.0) + babel-plugin-styled-components: 2.1.4(@babel/core@7.28.6)(styled-components@5.3.11(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react-is@19.2.4)(react@19.2.3))(supports-color@5.5.0) css-to-react-native: 3.2.0 hoist-non-react-statics: 3.3.2 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - react-is: 18.3.1 + react-is: 19.2.4 shallowequal: 1.1.0 supports-color: 5.5.0 transitivePeerDependencies: @@ -20870,6 +17111,21 @@ snapshots: core-util-is: 1.0.2 extsprintf: 1.3.0 + vite@6.4.1(@types/node@20.19.27)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.57.1 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 20.19.27 + fsevents: 2.3.3 + jiti: 2.6.1 + tsx: 4.21.0 + yaml: 2.8.2 + walk-up-path@3.0.1: {} walker@1.0.8: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 05b598ac6..d612388cd 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,6 +2,7 @@ packages: - 'packages/*' - 'pgpm/*' - 'graphql/*' + - 'examples/*' - 'uploads/*' - 'postgres/*' - 'graphile/*' diff --git a/postgres/drizzle-orm-test/package.json b/postgres/drizzle-orm-test/package.json index 4b15c990f..0865d5ba1 100644 --- a/postgres/drizzle-orm-test/package.json +++ b/postgres/drizzle-orm-test/package.json @@ -48,7 +48,7 @@ "devDependencies": { "@types/pg": "^8.16.0", "drizzle-orm": "^0.45.1", - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "pgsql-test": "workspace:^" diff --git a/postgres/introspectron/package.json b/postgres/introspectron/package.json index 7e47ca133..fe16057c1 100644 --- a/postgres/introspectron/package.json +++ b/postgres/introspectron/package.json @@ -32,7 +32,7 @@ "@constructive-io/graphql-test": "workspace:^", "@jest/test-sequencer": "^30.2.0", "@types/pg": "^8.16.0", - "makage": "^0.1.10", + "makage": "^0.1.12", "pgsql-test": "workspace:^" }, "dependencies": { diff --git a/postgres/pg-ast/package.json b/postgres/pg-ast/package.json index 1b6b54ef6..8339b76a2 100644 --- a/postgres/pg-ast/package.json +++ b/postgres/pg-ast/package.json @@ -37,7 +37,7 @@ "parse" ], "devDependencies": { - "makage": "^0.1.10", + "makage": "^0.1.12", "pg-proto-parser": "^1.30.4", "pgsql-deparser": "^17.17.2" }, diff --git a/postgres/pg-cache/package.json b/postgres/pg-cache/package.json index 489515ad9..f179ebb3c 100644 --- a/postgres/pg-cache/package.json +++ b/postgres/pg-cache/package.json @@ -37,7 +37,7 @@ }, "devDependencies": { "@types/pg": "^8.16.0", - "makage": "^0.1.10" + "makage": "^0.1.12" }, "keywords": [ "postgresql", diff --git a/postgres/pg-codegen/package.json b/postgres/pg-codegen/package.json index cdf47af28..a9d751a27 100644 --- a/postgres/pg-codegen/package.json +++ b/postgres/pg-codegen/package.json @@ -52,6 +52,6 @@ "devDependencies": { "@types/babel__generator": "^7.6.8", "@types/pg": "^8.16.0", - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/postgres/pg-env/package.json b/postgres/pg-env/package.json index a81ee9a7c..6e643fdbc 100644 --- a/postgres/pg-env/package.json +++ b/postgres/pg-env/package.json @@ -36,6 +36,6 @@ "constructive" ], "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/postgres/pg-query-context/package.json b/postgres/pg-query-context/package.json index 39986d9c2..2088cd8d0 100644 --- a/postgres/pg-query-context/package.json +++ b/postgres/pg-query-context/package.json @@ -33,7 +33,7 @@ }, "devDependencies": { "@types/pg": "^8.16.0", - "makage": "^0.1.10" + "makage": "^0.1.12" }, "keywords": [ "postgresql", diff --git a/postgres/pg-seed/package.json b/postgres/pg-seed/package.json index ff4b9188d..9c5046856 100644 --- a/postgres/pg-seed/package.json +++ b/postgres/pg-seed/package.json @@ -44,7 +44,7 @@ "devDependencies": { "@types/pg": "^8.16.0", "@types/pg-copy-streams": "^1.2.5", - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "csv-parse": "^6.1.0", diff --git a/postgres/pgsql-client/package.json b/postgres/pgsql-client/package.json index 8ff26be5f..55ce24842 100644 --- a/postgres/pgsql-client/package.json +++ b/postgres/pgsql-client/package.json @@ -42,7 +42,7 @@ }, "devDependencies": { "@types/pg": "^8.16.0", - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@pgpmjs/core": "workspace:^", diff --git a/postgres/pgsql-seed/package.json b/postgres/pgsql-seed/package.json index 59beede5d..91bfe8e11 100644 --- a/postgres/pgsql-seed/package.json +++ b/postgres/pgsql-seed/package.json @@ -43,7 +43,7 @@ }, "devDependencies": { "@types/pg": "^8.16.0", - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@pgpmjs/core": "workspace:^", diff --git a/postgres/pgsql-test/package.json b/postgres/pgsql-test/package.json index 2d6c8249a..f8bdb79d5 100644 --- a/postgres/pgsql-test/package.json +++ b/postgres/pgsql-test/package.json @@ -58,7 +58,7 @@ "@pgpmjs/core": "workspace:*", "@types/pg": "^8.16.0", "@types/pg-copy-streams": "^1.2.5", - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@pgpmjs/env": "workspace:^", diff --git a/postgres/supabase-test/package.json b/postgres/supabase-test/package.json index ed28e7c37..f528dcf01 100644 --- a/postgres/supabase-test/package.json +++ b/postgres/supabase-test/package.json @@ -58,6 +58,6 @@ "pgsql-test": "workspace:^" }, "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/uploads/content-type-stream/package.json b/uploads/content-type-stream/package.json index d8e5daf02..9f8c9e267 100644 --- a/uploads/content-type-stream/package.json +++ b/uploads/content-type-stream/package.json @@ -39,6 +39,6 @@ "middleware" ], "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/uploads/etag-hash/package.json b/uploads/etag-hash/package.json index 299770226..fe3f1cdce 100644 --- a/uploads/etag-hash/package.json +++ b/uploads/etag-hash/package.json @@ -38,6 +38,6 @@ "md5" ], "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/uploads/etag-stream/package.json b/uploads/etag-stream/package.json index 3b2eda77f..acb4ab74f 100644 --- a/uploads/etag-stream/package.json +++ b/uploads/etag-stream/package.json @@ -38,6 +38,6 @@ }, "devDependencies": { "glob": "^13.0.0", - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/uploads/mime-bytes/package.json b/uploads/mime-bytes/package.json index 073102f3a..59d9970b2 100644 --- a/uploads/mime-bytes/package.json +++ b/uploads/mime-bytes/package.json @@ -31,6 +31,6 @@ "keywords": [], "devDependencies": { "glob": "^13.0.0", - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/uploads/s3-streamer/package.json b/uploads/s3-streamer/package.json index ffd3d78c5..950be0d50 100644 --- a/uploads/s3-streamer/package.json +++ b/uploads/s3-streamer/package.json @@ -32,7 +32,7 @@ "@constructive-io/s3-utils": "workspace:^", "@pgpmjs/env": "workspace:^", "glob": "^13.0.0", - "makage": "^0.1.10" + "makage": "^0.1.12" }, "dependencies": { "@aws-sdk/client-s3": "^3.971.0", diff --git a/uploads/s3-utils/package.json b/uploads/s3-utils/package.json index a48ada548..7d9ea8479 100644 --- a/uploads/s3-utils/package.json +++ b/uploads/s3-utils/package.json @@ -35,6 +35,6 @@ }, "devDependencies": { "@types/node": "^18.19.69", - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/uploads/stream-to-etag/package.json b/uploads/stream-to-etag/package.json index 9420bf33f..8dc5af025 100644 --- a/uploads/stream-to-etag/package.json +++ b/uploads/stream-to-etag/package.json @@ -39,6 +39,6 @@ }, "devDependencies": { "glob": "^13.0.0", - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/uploads/upload-names/package.json b/uploads/upload-names/package.json index de91b8098..a92672735 100644 --- a/uploads/upload-names/package.json +++ b/uploads/upload-names/package.json @@ -31,6 +31,6 @@ "keywords": [], "devDependencies": { "glob": "^13.0.0", - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/uploads/uuid-hash/package.json b/uploads/uuid-hash/package.json index 3bd20720d..eced6bfaf 100644 --- a/uploads/uuid-hash/package.json +++ b/uploads/uuid-hash/package.json @@ -35,6 +35,6 @@ "uuid" ], "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" } } diff --git a/uploads/uuid-stream/package.json b/uploads/uuid-stream/package.json index 303751fd2..5b9a804e6 100644 --- a/uploads/uuid-stream/package.json +++ b/uploads/uuid-stream/package.json @@ -39,6 +39,6 @@ "uuid-hash": "workspace:^" }, "devDependencies": { - "makage": "^0.1.10" + "makage": "^0.1.12" } }