From ecc607b850d12a493991b0440886714112429d1b Mon Sep 17 00:00:00 2001 From: yyyyaaa Date: Fri, 6 Feb 2026 01:59:57 +0700 Subject: [PATCH 01/17] refactor: use ORM mode as core for RQ mode --- CLAUDE.md | 144 +- .../codegen/examples/example.schema.graphql | 593 ++++++ .../codegen/examples/multi-target.config.ts | 15 + graphql/codegen/jest.config.js | 6 +- .../client-generator.test.ts.snap | 27 +- .../model-generator.test.ts.snap | 136 +- .../react-query-hooks.test.ts.snap | 1820 +++++++---------- .../codegen/client-generator.test.ts | 26 +- .../__tests__/codegen/format-output.test.ts | 3 +- .../codegen/input-types-generator.test.ts | 140 +- .../__tests__/codegen/model-generator.test.ts | 32 +- .../__tests__/codegen/query-builder.test.ts | 56 +- .../codegen/query-keys-factory.test.ts | 120 +- .../codegen/react-query-hooks.test.ts | 148 +- .../codegen/react-query-optional.test.ts | 46 +- .../src/__tests__/codegen/scalars.test.ts | 6 +- .../codegen/schema-types-generator.test.ts | 46 +- .../src/__tests__/codegen/utils.test.ts | 40 +- .../__tests__/config/resolve-config.test.ts | 26 +- .../__tests__/introspect/infer-tables.test.ts | 250 +-- graphql/codegen/src/cli/index.ts | 35 +- graphql/codegen/src/cli/shared.ts | 29 +- graphql/codegen/src/client/error.ts | 70 +- graphql/codegen/src/client/execute.ts | 16 +- graphql/codegen/src/client/index.ts | 20 +- graphql/codegen/src/client/typed-document.ts | 2 +- graphql/codegen/src/core/ast.ts | 279 ++- graphql/codegen/src/core/codegen/babel-ast.ts | 6 +- graphql/codegen/src/core/codegen/barrel.ts | 55 +- graphql/codegen/src/core/codegen/client.ts | 96 +- .../src/core/codegen/custom-mutations.ts | 334 ++- .../src/core/codegen/custom-queries.ts | 706 +++---- graphql/codegen/src/core/codegen/gql-ast.ts | 405 ---- graphql/codegen/src/core/codegen/index.ts | 212 +- .../codegen/src/core/codegen/invalidation.ts | 21 +- .../codegen/src/core/codegen/mutation-keys.ts | 27 +- graphql/codegen/src/core/codegen/mutations.ts | 1040 +++------- .../codegen/src/core/codegen/orm/barrel.ts | 9 +- .../src/core/codegen/orm/client-generator.ts | 31 +- .../codegen/src/core/codegen/orm/client.ts | 12 +- .../core/codegen/orm/custom-ops-generator.ts | 263 ++- graphql/codegen/src/core/codegen/orm/index.ts | 42 +- .../core/codegen/orm/input-types-generator.ts | 144 +- .../src/core/codegen/orm/model-generator.ts | 278 ++- graphql/codegen/src/core/codegen/queries.ts | 1511 +++----------- .../codegen/src/core/codegen/query-keys.ts | 14 +- graphql/codegen/src/core/codegen/scalars.ts | 6 +- .../src/core/codegen/schema-gql-ast.ts | 518 ----- .../core/codegen/schema-types-generator.ts | 15 +- .../src/core/codegen/select-helpers.ts | 90 + .../codegen/src/core/codegen/shared/index.ts | 25 +- .../core/codegen/templates/client.browser.ts | 271 --- .../src/core/codegen/templates/client.node.ts | 337 --- .../src/core/codegen/templates/orm-client.ts | 16 +- .../core/codegen/templates/query-builder.ts | 281 ++- .../core/codegen/templates/select-types.ts | 11 +- .../codegen/src/core/codegen/type-resolver.ts | 71 +- graphql/codegen/src/core/codegen/types.ts | 25 +- graphql/codegen/src/core/codegen/utils.ts | 45 +- graphql/codegen/src/core/config/index.ts | 7 +- graphql/codegen/src/core/config/loader.ts | 11 +- graphql/codegen/src/core/config/resolver.ts | 18 +- graphql/codegen/src/core/custom-ast.ts | 48 +- graphql/codegen/src/core/database/index.ts | 5 +- graphql/codegen/src/core/generate.ts | 48 +- graphql/codegen/src/core/index.ts | 6 +- .../src/core/introspect/fetch-schema.ts | 31 +- graphql/codegen/src/core/introspect/index.ts | 20 +- .../src/core/introspect/infer-tables.ts | 63 +- .../src/core/introspect/source/api-schemas.ts | 10 +- .../src/core/introspect/source/database.ts | 7 +- .../src/core/introspect/source/endpoint.ts | 6 +- .../src/core/introspect/source/file.ts | 4 +- .../src/core/introspect/source/index.ts | 108 +- .../src/core/introspect/source/pgpm-module.ts | 12 +- .../src/core/introspect/transform-schema.ts | 38 +- .../codegen/src/core/meta-object/convert.ts | 12 +- .../codegen/src/core/meta-object/validate.ts | 4 +- graphql/codegen/src/core/output/index.ts | 4 +- graphql/codegen/src/core/output/writer.ts | 8 +- graphql/codegen/src/core/pipeline/index.ts | 24 +- graphql/codegen/src/core/query-builder.ts | 56 +- graphql/codegen/src/core/watch/cache.ts | 1 + graphql/codegen/src/core/watch/index.ts | 18 +- .../codegen/src/core/watch/orchestrator.ts | 50 +- graphql/codegen/src/core/watch/poller.ts | 15 +- .../codegen/src/generators/field-selector.ts | 94 +- graphql/codegen/src/generators/index.ts | 16 +- graphql/codegen/src/generators/mutations.ts | 97 +- graphql/codegen/src/generators/select.ts | 187 +- graphql/codegen/src/index.ts | 14 +- graphql/codegen/src/types/config.ts | 18 +- graphql/codegen/src/types/index.ts | 39 +- 93 files changed, 4891 insertions(+), 7256 deletions(-) create mode 100644 graphql/codegen/examples/example.schema.graphql create mode 100644 graphql/codegen/examples/multi-target.config.ts delete mode 100644 graphql/codegen/src/core/codegen/gql-ast.ts delete mode 100644 graphql/codegen/src/core/codegen/schema-gql-ast.ts create mode 100644 graphql/codegen/src/core/codegen/select-helpers.ts delete mode 100644 graphql/codegen/src/core/codegen/templates/client.browser.ts delete mode 100644 graphql/codegen/src/core/codegen/templates/client.node.ts 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/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..31e4f0863 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 @@ -107,13 +107,13 @@ exports[`client-generator generateOrmClientFile generates OrmClient class with e import type { GraphQLAdapter, GraphQLError, - QueryResult, + QueryResult } from '@constructive-io/graphql-types'; export type { GraphQLAdapter, GraphQLError, - QueryResult, + QueryResult } from '@constructive-io/graphql-types'; /** @@ -139,19 +139,19 @@ export class FetchAdapter implements GraphQLAdapter { headers: { 'Content-Type': 'application/json', Accept: 'application/json', - ...this.headers, + ...this.headers }, body: JSON.stringify({ query: document, - variables: variables ?? {}, - }), + variables: variables ?? {} + }) }); if (!response.ok) { return { ok: false, data: null, - errors: [{ message: \`HTTP \${response.status}: \${response.statusText}\` }], + errors: [{ message: \`HTTP \${response.status}: \${response.statusText}\` }] }; } @@ -164,14 +164,14 @@ export class FetchAdapter implements GraphQLAdapter { return { ok: false, data: null, - errors: json.errors, + errors: json.errors }; } return { ok: true, data: json.data as T, - errors: undefined, + errors: undefined }; } @@ -301,8 +301,17 @@ 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; } /** 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..fafb3a3d1 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,21 @@ 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 { QueryBuilder, buildFindManyDocument, buildFindFirstDocument, buildFindOneDocument, buildCreateDocument, buildUpdateByPkDocument, buildDeleteByPkDocument } from "../query-builder"; import type { ConnectionResult, FindManyArgs, FindFirstArgs, CreateArgs, UpdateArgs, DeleteArgs, InferSelectResult, DeepExact } from "../select-types"; import type { User, UserWithRelations, UserSelect, UserFilter, UsersOrderBy, CreateUserInput, UpdateUserInput, UserPatch } from "../input-types"; +const defaultSelect = { + id: true +} as const; export class UserModel { constructor(private client: OrmClient) {} - findMany(args?: FindManyArgs, UserFilter, UsersOrderBy>): QueryBuilder<{ + findMany(args?: FindManyArgs, UserFilter, UsersOrderBy>): QueryBuilder<{ users: ConnectionResult>; }> { const { document, variables - } = buildFindManyDocument("User", "users", args?.select, { + } = buildFindManyDocument("User", "users", args?.select ?? defaultSelect, { where: args?.where, orderBy: args?.orderBy as string[] | undefined, first: args?.first, @@ -36,7 +39,7 @@ export class UserModel { variables }); } - findFirst(args?: FindFirstArgs, UserFilter>): QueryBuilder<{ + findFirst(args?: FindFirstArgs, UserFilter>): QueryBuilder<{ users: { nodes: InferSelectResult[]; }; @@ -44,7 +47,7 @@ export class UserModel { const { document, variables - } = buildFindFirstDocument("User", "users", args?.select, { + } = buildFindFirstDocument("User", "users", args?.select ?? defaultSelect, { where: args?.where }, "UserFilter"); return new QueryBuilder({ @@ -56,7 +59,26 @@ export class UserModel { variables }); } - create(args: CreateArgs, CreateUserInput["user"]>): QueryBuilder<{ + findOne(args: { + id: string; + select?: DeepExact; + }): QueryBuilder<{ + user: InferSelectResult | null; + }> { + const { + document, + variables + } = buildFindOneDocument("User", "user", args.id, args.select ?? defaultSelect, "id", "UUID!"); + return new QueryBuilder({ + client: this.client, + operation: "query", + operationName: "User", + fieldName: "user", + document, + variables + }); + } + create(args: CreateArgs, CreateUserInput["user"]>): QueryBuilder<{ createUser: { user: InferSelectResult; }; @@ -64,7 +86,7 @@ export class UserModel { const { document, variables - } = buildCreateDocument("User", "createUser", "user", args.select, args.data, "CreateUserInput"); + } = buildCreateDocument("User", "createUser", "user", args.select ?? defaultSelect, args.data, "CreateUserInput"); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -74,7 +96,7 @@ export class UserModel { variables }); } - update(args: UpdateArgs, { + update(args: UpdateArgs, { id: string; }, UserPatch>): QueryBuilder<{ updateUser: { @@ -84,7 +106,7 @@ export class UserModel { const { document, variables - } = buildUpdateDocument("User", "updateUser", "user", args.select, args.where, args.data, "UpdateUserInput"); + } = buildUpdateByPkDocument("User", "updateUser", "user", args.select ?? defaultSelect, args.where.id, args.data, "UpdateUserInput", "id"); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -94,19 +116,17 @@ export class UserModel { variables }); } - delete(args: DeleteArgs<{ + delete(args: DeleteArgs<{ id: string; - }>): QueryBuilder<{ + }, DeepExact>): QueryBuilder<{ deleteUser: { - user: { - id: string; - }; + user: InferSelectResult; }; }> { const { document, variables - } = buildDeleteDocument("User", "deleteUser", "user", args.where, "DeleteUserInput"); + } = buildDeleteByPkDocument("User", "deleteUser", "user", args.where.id, "DeleteUserInput", "id", args.select ?? defaultSelect); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -126,18 +146,21 @@ 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 { QueryBuilder, buildFindManyDocument, buildFindFirstDocument, buildFindOneDocument, buildCreateDocument, buildUpdateByPkDocument, buildDeleteByPkDocument } from "../query-builder"; import type { ConnectionResult, FindManyArgs, FindFirstArgs, CreateArgs, UpdateArgs, DeleteArgs, InferSelectResult, DeepExact } from "../select-types"; import type { AuditLog, AuditLogWithRelations, AuditLogSelect, AuditLogFilter, AuditLogsOrderBy, CreateAuditLogInput, UpdateAuditLogInput, AuditLogPatch } from "../input-types"; +const defaultSelect = { + id: true +} as const; export class AuditLogModel { constructor(private client: OrmClient) {} - findMany(args?: FindManyArgs, AuditLogFilter, AuditLogsOrderBy>): QueryBuilder<{ + findMany(args?: FindManyArgs, AuditLogFilter, AuditLogsOrderBy>): QueryBuilder<{ auditLogs: ConnectionResult>; }> { const { document, variables - } = buildFindManyDocument("AuditLog", "auditLogs", args?.select, { + } = buildFindManyDocument("AuditLog", "auditLogs", args?.select ?? defaultSelect, { where: args?.where, orderBy: args?.orderBy as string[] | undefined, first: args?.first, @@ -155,7 +178,7 @@ export class AuditLogModel { variables }); } - findFirst(args?: FindFirstArgs, AuditLogFilter>): QueryBuilder<{ + findFirst(args?: FindFirstArgs, AuditLogFilter>): QueryBuilder<{ auditLogs: { nodes: InferSelectResult[]; }; @@ -163,7 +186,7 @@ export class AuditLogModel { const { document, variables - } = buildFindFirstDocument("AuditLog", "auditLogs", args?.select, { + } = buildFindFirstDocument("AuditLog", "auditLogs", args?.select ?? defaultSelect, { where: args?.where }, "AuditLogFilter"); return new QueryBuilder({ @@ -175,7 +198,26 @@ export class AuditLogModel { variables }); } - create(args: CreateArgs, CreateAuditLogInput["auditLog"]>): QueryBuilder<{ + findOne(args: { + id: string; + select?: DeepExact; + }): QueryBuilder<{ + auditLog: InferSelectResult | null; + }> { + const { + document, + variables + } = buildFindOneDocument("AuditLog", "auditLog", args.id, args.select ?? defaultSelect, "id", "UUID!"); + return new QueryBuilder({ + client: this.client, + operation: "query", + operationName: "AuditLog", + fieldName: "auditLog", + document, + variables + }); + } + create(args: CreateArgs, CreateAuditLogInput["auditLog"]>): QueryBuilder<{ createAuditLog: { auditLog: InferSelectResult; }; @@ -183,7 +225,7 @@ export class AuditLogModel { const { document, variables - } = buildCreateDocument("AuditLog", "createAuditLog", "auditLog", args.select, args.data, "CreateAuditLogInput"); + } = buildCreateDocument("AuditLog", "createAuditLog", "auditLog", args.select ?? defaultSelect, args.data, "CreateAuditLogInput"); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -203,18 +245,21 @@ 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 { QueryBuilder, buildFindManyDocument, buildFindFirstDocument, buildFindOneDocument, buildCreateDocument, buildUpdateByPkDocument, buildDeleteByPkDocument } from "../query-builder"; import type { ConnectionResult, FindManyArgs, FindFirstArgs, CreateArgs, UpdateArgs, DeleteArgs, InferSelectResult, DeepExact } from "../select-types"; import type { Organization, OrganizationWithRelations, OrganizationSelect, OrganizationFilter, OrganizationsOrderBy, CreateOrganizationInput, UpdateOrganizationInput, OrganizationPatch } from "../input-types"; +const defaultSelect = { + id: true +} as const; export class OrganizationModel { constructor(private client: OrmClient) {} - findMany(args?: FindManyArgs, OrganizationFilter, OrganizationsOrderBy>): QueryBuilder<{ + findMany(args?: FindManyArgs, OrganizationFilter, OrganizationsOrderBy>): QueryBuilder<{ allOrganizations: ConnectionResult>; }> { const { document, variables - } = buildFindManyDocument("Organization", "allOrganizations", args?.select, { + } = buildFindManyDocument("Organization", "allOrganizations", args?.select ?? defaultSelect, { where: args?.where, orderBy: args?.orderBy as string[] | undefined, first: args?.first, @@ -232,7 +277,7 @@ export class OrganizationModel { variables }); } - findFirst(args?: FindFirstArgs, OrganizationFilter>): QueryBuilder<{ + findFirst(args?: FindFirstArgs, OrganizationFilter>): QueryBuilder<{ allOrganizations: { nodes: InferSelectResult[]; }; @@ -240,7 +285,7 @@ export class OrganizationModel { const { document, variables - } = buildFindFirstDocument("Organization", "allOrganizations", args?.select, { + } = buildFindFirstDocument("Organization", "allOrganizations", args?.select ?? defaultSelect, { where: args?.where }, "OrganizationFilter"); return new QueryBuilder({ @@ -252,7 +297,26 @@ export class OrganizationModel { variables }); } - create(args: CreateArgs, CreateOrganizationInput["organization"]>): QueryBuilder<{ + findOne(args: { + id: string; + select?: DeepExact; + }): QueryBuilder<{ + organizationById: InferSelectResult | null; + }> { + const { + document, + variables + } = buildFindOneDocument("Organization", "organizationById", args.id, args.select ?? defaultSelect, "id", "UUID!"); + return new QueryBuilder({ + client: this.client, + operation: "query", + operationName: "Organization", + fieldName: "organizationById", + document, + variables + }); + } + create(args: CreateArgs, CreateOrganizationInput["organization"]>): QueryBuilder<{ registerOrganization: { organization: InferSelectResult; }; @@ -260,7 +324,7 @@ export class OrganizationModel { const { document, variables - } = buildCreateDocument("Organization", "registerOrganization", "organization", args.select, args.data, "CreateOrganizationInput"); + } = buildCreateDocument("Organization", "registerOrganization", "organization", args.select ?? defaultSelect, args.data, "CreateOrganizationInput"); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -270,7 +334,7 @@ export class OrganizationModel { variables }); } - update(args: UpdateArgs, { + update(args: UpdateArgs, { id: string; }, OrganizationPatch>): QueryBuilder<{ modifyOrganization: { @@ -280,7 +344,7 @@ export class OrganizationModel { const { document, variables - } = buildUpdateDocument("Organization", "modifyOrganization", "organization", args.select, args.where, args.data, "UpdateOrganizationInput"); + } = buildUpdateByPkDocument("Organization", "modifyOrganization", "organization", args.select ?? defaultSelect, args.where.id, args.data, "UpdateOrganizationInput", "id"); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -290,19 +354,17 @@ export class OrganizationModel { variables }); } - delete(args: DeleteArgs<{ + delete(args: DeleteArgs<{ id: string; - }>): QueryBuilder<{ + }, DeepExact>): QueryBuilder<{ removeOrganization: { - organization: { - id: string; - }; + organization: InferSelectResult; }; }> { const { document, variables - } = buildDeleteDocument("Organization", "removeOrganization", "organization", args.where, "DeleteOrganizationInput"); + } = buildDeleteByPkDocument("Organization", "removeOrganization", "organization", args.where.id, "DeleteOrganizationInput", "id", args.select ?? defaultSelect); return new QueryBuilder({ client: this.client, operation: "mutation", 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..1e1d1710d 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 @@ -57,8 +57,6 @@ exports[`Barrel File Generators generateMainBarrel generates main barrel with al * \`\`\` */ export * from "./client"; -export * from "./types"; -export * from "./schema-types"; export * from "./query-keys"; export * from "./mutation-keys"; export * from "./invalidation"; @@ -97,7 +95,6 @@ exports[`Barrel File Generators generateMainBarrel generates main barrel without * \`\`\` */ export * from "./client"; -export * from "./types"; export * from "./queries"; export * from "./mutations";" `; @@ -133,8 +130,6 @@ exports[`Barrel File Generators generateMainBarrel generates main barrel without * \`\`\` */ export * from "./client"; -export * from "./types"; -export * from "./schema-types"; export * from "./queries";" `; @@ -192,33 +187,30 @@ exports[`Custom Mutation Hook Generators generateCustomMutationHook generates cu * DO NOT EDIT - changes will be overwritten */ -import { useMutation } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { LoginPayload } from "../schema-types"; -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 { useMutation } from '@tanstack/react-query'; +import type { UseMutationOptions } from '@tanstack/react-query'; +import { getClient } from '../client'; +import { customMutationKeys } from '../mutation-keys'; +import type { LoginVariables } from '../../orm/mutation'; +import type { LoginPayloadSelect, LoginPayload } from '../../orm/input-types'; +import type { DeepExact, InferSelectResult } from '../../orm/select-types'; + +export type { LoginVariables } from '../../orm/mutation'; +export type { LoginPayloadSelect } from '../../orm/input-types'; + +const defaultSelect = { token: true } as const; + +export function useLoginMutation( + args?: { select?: DeepExact }, + options?: Omit }, Error, LoginVariables>, 'mutationFn'> +) { return useMutation({ mutationKey: customMutationKeys.login(), - mutationFn: (variables: LoginMutationVariables) => execute(loginMutationDocument, variables), - ...options + mutationFn: (variables: LoginVariables) => getClient().mutation.login(variables, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + ...options, }); -}" +} +" `; exports[`Custom Mutation Hook Generators generateCustomMutationHook generates custom mutation hook with input object argument 1`] = ` @@ -228,32 +220,30 @@ exports[`Custom Mutation Hook Generators generateCustomMutationHook generates cu * DO NOT EDIT - changes will be overwritten */ -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 { 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 { useMutation } from '@tanstack/react-query'; +import type { UseMutationOptions } from '@tanstack/react-query'; +import { getClient } from '../client'; +import { customMutationKeys } from '../mutation-keys'; +import type { RegisterVariables } from '../../orm/mutation'; +import type { RegisterPayloadSelect, RegisterPayload } from '../../orm/input-types'; +import type { DeepExact, InferSelectResult } from '../../orm/select-types'; + +export type { RegisterVariables } from '../../orm/mutation'; +export type { RegisterPayloadSelect } from '../../orm/input-types'; + +const defaultSelect = { token: true } as const; + +export function useRegisterMutation( + args?: { select?: DeepExact }, + options?: Omit }, Error, RegisterVariables>, 'mutationFn'> +) { return useMutation({ mutationKey: customMutationKeys.register(), - mutationFn: (variables: RegisterMutationVariables) => execute(registerMutationDocument, variables), - ...options + mutationFn: (variables: RegisterVariables) => getClient().mutation.register(variables, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + ...options, }); -}" +} +" `; exports[`Custom Mutation Hook Generators generateCustomMutationHook generates custom mutation hook without arguments 1`] = ` @@ -263,29 +253,28 @@ exports[`Custom Mutation Hook Generators generateCustomMutationHook generates cu * DO NOT EDIT - changes will be overwritten */ -import { useMutation } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { LogoutPayload } from "../schema-types"; -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 { useMutation } from '@tanstack/react-query'; +import type { UseMutationOptions } from '@tanstack/react-query'; +import { getClient } from '../client'; +import { customMutationKeys } from '../mutation-keys'; +import type { LogoutPayloadSelect, LogoutPayload } from '../../orm/input-types'; +import type { DeepExact, InferSelectResult } from '../../orm/select-types'; + +export type { LogoutPayloadSelect } from '../../orm/input-types'; + +const defaultSelect = { success: true } as const; + +export function useLogoutMutation( + args?: { select?: DeepExact }, + options?: Omit }, Error, void>, 'mutationFn'> +) { return useMutation({ mutationKey: customMutationKeys.logout(), - mutationFn: () => execute(logoutMutationDocument), - ...options + mutationFn: () => getClient().mutation.logout({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + ...options, }); -}" +} +" `; exports[`Custom Mutation Hook Generators generateCustomMutationHook generates custom mutation hook without centralized keys 1`] = ` @@ -295,31 +284,28 @@ exports[`Custom Mutation Hook Generators generateCustomMutationHook generates cu * DO NOT EDIT - changes will be overwritten */ -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 { useMutation } from '@tanstack/react-query'; +import type { UseMutationOptions } from '@tanstack/react-query'; +import { getClient } from '../client'; +import type { LoginVariables } from '../../orm/mutation'; +import type { LoginPayloadSelect, LoginPayload } from '../../orm/input-types'; +import type { DeepExact, InferSelectResult } from '../../orm/select-types'; + +export type { LoginVariables } from '../../orm/mutation'; +export type { LoginPayloadSelect } from '../../orm/input-types'; + +const defaultSelect = { token: true } as const; + +export function useLoginMutation( + args?: { select?: DeepExact }, + options?: Omit }, Error, LoginVariables>, 'mutationFn'> +) { return useMutation({ - mutationFn: (variables: LoginMutationVariables) => execute(loginMutationDocument, variables), - ...options + mutationFn: (variables: LoginVariables) => getClient().mutation.login(variables, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + ...options, }); -}" +} +" `; exports[`Custom Query Hook Generators generateCustomQueryHook generates custom query hook with arguments 1`] = ` @@ -329,72 +315,81 @@ exports[`Custom Query Hook Generators generateCustomQueryHook generates custom q * DO NOT EDIT - changes will be overwritten */ -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 { 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 { useQuery } from '@tanstack/react-query'; +import type { UseQueryOptions, QueryClient } from '@tanstack/react-query'; +import { getClient } from '../client'; +import { customQueryKeys } from '../query-keys'; +import type { SearchUsersVariables } from '../../orm/query'; +import type { UserSelect, User } from '../../orm/input-types'; +import type { DeepExact, InferSelectResult } from '../../orm/select-types'; + +export type { SearchUsersVariables } from '../../orm/query'; +export type { UserSelect } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + /** Query key factory - re-exported from query-keys.ts */ export const searchUsersQueryKey = customQueryKeys.searchUsers; + /** * Search users by name or email - * + * * @example * \`\`\`tsx * const { data, isLoading } = useSearchUsersQuery({ query, limit }); - * + * * if (data?.searchUsers) { * console.log(data.searchUsers); * } * \`\`\` */ -export function useSearchUsersQuery(variables: SearchUsersQueryVariables, options?: Omit, 'queryKey' | 'queryFn'>) { +export function useSearchUsersQuery( + variables: SearchUsersVariables, + args?: { select?: DeepExact }, + options?: Omit[] }, Error>, 'queryKey' | 'queryFn'> +) { return useQuery({ queryKey: searchUsersQueryKey(variables), - queryFn: () => execute(searchUsersQueryDocument, variables), + queryFn: () => getClient().query.searchUsers(variables!, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), enabled: !!variables && options?.enabled !== false, - ...options + ...options, }); } + /** * Fetch searchUsers without React hooks - * + * * @example * \`\`\`ts * const data = await fetchSearchUsersQuery({ query, limit }); * \`\`\` */ -export async function fetchSearchUsersQuery(variables: SearchUsersQueryVariables, options?: ExecuteOptions): Promise { - return execute(searchUsersQueryDocument, variables, options); +export async function fetchSearchUsersQuery( + variables: SearchUsersVariables, + args?: { select?: DeepExact } +) { + return getClient().query.searchUsers(variables!, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(); } + /** * Prefetch searchUsers for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchSearchUsersQuery(queryClient, { query, limit }); * \`\`\` */ -export async function prefetchSearchUsersQuery(queryClient: QueryClient, variables: SearchUsersQueryVariables, options?: ExecuteOptions): Promise { +export async function prefetchSearchUsersQuery( + queryClient: QueryClient, + variables: SearchUsersVariables, + args?: { select?: DeepExact } +): Promise { await queryClient.prefetchQuery({ queryKey: searchUsersQueryKey(variables), - queryFn: () => execute(searchUsersQueryDocument, variables, options) + queryFn: () => getClient().query.searchUsers(variables!, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), }); -}" +} +" `; exports[`Custom Query Hook Generators generateCustomQueryHook generates custom query hook without arguments 1`] = ` @@ -404,67 +399,75 @@ exports[`Custom Query Hook Generators generateCustomQueryHook generates custom q * DO NOT EDIT - changes will be overwritten */ -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 { customQueryKeys } from "../query-keys"; -/** GraphQL query document */ -export const currentUserQueryDocument = \` -query CurrentUserQuery { - currentUser -} -\`; -export interface CurrentUserQueryResult { - currentUser: User; -} +import { useQuery } from '@tanstack/react-query'; +import type { UseQueryOptions, QueryClient } from '@tanstack/react-query'; +import { getClient } from '../client'; +import { customQueryKeys } from '../query-keys'; +import type { UserSelect, User } from '../../orm/input-types'; +import type { DeepExact, InferSelectResult } from '../../orm/select-types'; + +export type { UserSelect } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + /** Query key factory - re-exported from query-keys.ts */ export const currentUserQueryKey = customQueryKeys.currentUser; + /** * Get the current authenticated user - * + * * @example * \`\`\`tsx * const { data, isLoading } = useCurrentUserQuery(); - * + * * if (data?.currentUser) { * console.log(data.currentUser); * } * \`\`\` */ -export function useCurrentUserQuery(options?: Omit, 'queryKey' | 'queryFn'>) { +export function useCurrentUserQuery( + args?: { select?: DeepExact }, + options?: Omit }, Error>, 'queryKey' | 'queryFn'> +) { return useQuery({ queryKey: currentUserQueryKey(), - queryFn: () => execute(currentUserQueryDocument), - ...options + queryFn: () => getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + ...options, }); } + /** * Fetch currentUser without React hooks - * + * * @example * \`\`\`ts * const data = await fetchCurrentUserQuery(); * \`\`\` */ -export async function fetchCurrentUserQuery(options?: ExecuteOptions): Promise { - return execute(currentUserQueryDocument, undefined, options); +export async function fetchCurrentUserQuery( + args?: { select?: DeepExact } +) { + return getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(); } + /** * Prefetch currentUser for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchCurrentUserQuery(queryClient); * \`\`\` */ -export async function prefetchCurrentUserQuery(queryClient: QueryClient, options?: ExecuteOptions): Promise { +export async function prefetchCurrentUserQuery( + queryClient: QueryClient, + args?: { select?: DeepExact } +): Promise { await queryClient.prefetchQuery({ queryKey: currentUserQueryKey(), - queryFn: () => execute(currentUserQueryDocument, undefined, options) + queryFn: () => getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), }); -}" +} +" `; exports[`Custom Query Hook Generators generateCustomQueryHook generates custom query hook without centralized keys 1`] = ` @@ -474,66 +477,74 @@ exports[`Custom Query Hook Generators generateCustomQueryHook generates custom q * DO NOT EDIT - changes will be overwritten */ -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 { useQuery } from '@tanstack/react-query'; +import type { UseQueryOptions, QueryClient } from '@tanstack/react-query'; +import { getClient } from '../client'; +import type { UserSelect, User } from '../../orm/input-types'; +import type { DeepExact, InferSelectResult } from '../../orm/select-types'; + +export type { UserSelect } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + /** Query key factory for caching */ -export const currentUserQueryKey = () => ["currentUser"] as const; +export const currentUserQueryKey = () => ['currentUser'] as const; + /** * Get the current authenticated user - * + * * @example * \`\`\`tsx * const { data, isLoading } = useCurrentUserQuery(); - * + * * if (data?.currentUser) { * console.log(data.currentUser); * } * \`\`\` */ -export function useCurrentUserQuery(options?: Omit, 'queryKey' | 'queryFn'>) { +export function useCurrentUserQuery( + args?: { select?: DeepExact }, + options?: Omit }, Error>, 'queryKey' | 'queryFn'> +) { return useQuery({ queryKey: currentUserQueryKey(), - queryFn: () => execute(currentUserQueryDocument), - ...options + queryFn: () => getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + ...options, }); } + /** * Fetch currentUser without React hooks - * + * * @example * \`\`\`ts * const data = await fetchCurrentUserQuery(); * \`\`\` */ -export async function fetchCurrentUserQuery(options?: ExecuteOptions): Promise { - return execute(currentUserQueryDocument, undefined, options); +export async function fetchCurrentUserQuery( + args?: { select?: DeepExact } +) { + return getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(); } + /** * Prefetch currentUser for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchCurrentUserQuery(queryClient); * \`\`\` */ -export async function prefetchCurrentUserQuery(queryClient: QueryClient, options?: ExecuteOptions): Promise { +export async function prefetchCurrentUserQuery( + queryClient: QueryClient, + args?: { select?: DeepExact } +): Promise { await queryClient.prefetchQuery({ queryKey: currentUserQueryKey(), - queryFn: () => execute(currentUserQueryDocument, undefined, options) + queryFn: () => getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), }); -}" +} +" `; exports[`Mutation Hook Generators generateCreateMutationHook generates create mutation hook for simple table 1`] = ` @@ -543,69 +554,52 @@ exports[`Mutation Hook Generators generateCreateMutationHook generates create mu * DO NOT EDIT - changes will be overwritten */ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { User } from "../types"; -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 { useMutation, useQueryClient } from '@tanstack/react-query'; +import type { UseMutationOptions } from '@tanstack/react-query'; +import { getClient } from '../client'; +import { userKeys } from '../query-keys'; +import { userMutationKeys } from '../mutation-keys'; +import type { + UserSelect, + UserWithRelations, + CreateUserInput, +} from '../../orm/input-types'; +import type { + DeepExact, + InferSelectResult, +} from '../../orm/select-types'; + +export type { UserSelect, UserWithRelations, CreateUserInput } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + /** * Mutation hook for creating a User - * + * * @example * \`\`\`tsx - * const { mutate, isPending } = useCreateUserMutation(); - * - * mutate({ - * input: { - * user: { - * // ... fields - * }, - * }, + * const { mutate, isPending } = useCreateUserMutation({ + * select: { id: true, name: true }, * }); + * + * mutate({ name: 'New item' }); * \`\`\` */ -export function useCreateUserMutation(options?: Omit, 'mutationFn'>) { +export function useCreateUserMutation( + args?: { select?: DeepExact }, + options?: Omit } }, Error, CreateUserInput['user']>, 'mutationFn'> +) { 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 ?? defaultSelect) as DeepExact }).unwrap(), onSuccess: () => { - queryClient.invalidateQueries({ - queryKey: userKeys.lists() - }); + queryClient.invalidateQueries({ queryKey: userKeys.lists() }); }, - ...options + ...options, }); -}" +} +" `; exports[`Mutation Hook Generators generateCreateMutationHook generates create mutation hook for table with relationships 1`] = ` @@ -615,74 +609,52 @@ exports[`Mutation Hook Generators generateCreateMutationHook generates create mu * DO NOT EDIT - changes will be overwritten */ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { Post } from "../types"; -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 { useMutation, useQueryClient } from '@tanstack/react-query'; +import type { UseMutationOptions } from '@tanstack/react-query'; +import { getClient } from '../client'; +import { postKeys } from '../query-keys'; +import { postMutationKeys } from '../mutation-keys'; +import type { + PostSelect, + PostWithRelations, + CreatePostInput, +} from '../../orm/input-types'; +import type { + DeepExact, + InferSelectResult, +} from '../../orm/select-types'; + +export type { PostSelect, PostWithRelations, CreatePostInput } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + /** * Mutation hook for creating a Post - * + * * @example * \`\`\`tsx - * const { mutate, isPending } = useCreatePostMutation(); - * - * mutate({ - * input: { - * post: { - * // ... fields - * }, - * }, + * const { mutate, isPending } = useCreatePostMutation({ + * select: { id: true, name: true }, * }); + * + * mutate({ name: 'New item' }); * \`\`\` */ -export function useCreatePostMutation(options?: Omit, 'mutationFn'>) { +export function useCreatePostMutation( + args?: { select?: DeepExact }, + options?: Omit } }, Error, CreatePostInput['post']>, 'mutationFn'> +) { 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 ?? defaultSelect) as DeepExact }).unwrap(), onSuccess: () => { - queryClient.invalidateQueries({ - queryKey: postKeys.lists() - }); + queryClient.invalidateQueries({ queryKey: postKeys.lists() }); }, - ...options + ...options, }); -}" +} +" `; exports[`Mutation Hook Generators generateCreateMutationHook generates create mutation hook without centralized keys 1`] = ` @@ -692,66 +664,49 @@ exports[`Mutation Hook Generators generateCreateMutationHook generates create mu * DO NOT EDIT - changes will be overwritten */ -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 { useMutation, useQueryClient } from '@tanstack/react-query'; +import type { UseMutationOptions } from '@tanstack/react-query'; +import { getClient } from '../client'; +import type { + UserSelect, + UserWithRelations, + CreateUserInput, +} from '../../orm/input-types'; +import type { + DeepExact, + InferSelectResult, +} from '../../orm/select-types'; + +export type { UserSelect, UserWithRelations, CreateUserInput } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + /** * Mutation hook for creating a User - * + * * @example * \`\`\`tsx - * const { mutate, isPending } = useCreateUserMutation(); - * - * mutate({ - * input: { - * user: { - * // ... fields - * }, - * }, + * const { mutate, isPending } = useCreateUserMutation({ + * select: { id: true, name: true }, * }); + * + * mutate({ name: 'New item' }); * \`\`\` */ -export function useCreateUserMutation(options?: Omit, 'mutationFn'>) { +export function useCreateUserMutation( + args?: { select?: DeepExact }, + options?: Omit } }, Error, CreateUserInput['user']>, 'mutationFn'> +) { const queryClient = useQueryClient(); return useMutation({ - mutationFn: (variables: CreateUserMutationVariables) => execute(createUserMutationDocument, variables), + mutationFn: (data: CreateUserInput['user']) => getClient().user.create({ data, select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), onSuccess: () => { - queryClient.invalidateQueries({ - queryKey: ["user", "list"] - }); + queryClient.invalidateQueries({ queryKey: ['user', 'list'] }); }, - ...options + ...options, }); -}" +} +" `; exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mutation hook for simple table 1`] = ` @@ -761,58 +716,52 @@ exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mu * DO NOT EDIT - changes will be overwritten */ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -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 { useMutation, useQueryClient } from '@tanstack/react-query'; +import type { UseMutationOptions } from '@tanstack/react-query'; +import { getClient } from '../client'; +import { userKeys } from '../query-keys'; +import { userMutationKeys } from '../mutation-keys'; +import type { + UserSelect, + UserWithRelations, +} from '../../orm/input-types'; +import type { + DeepExact, + InferSelectResult, +} from '../../orm/select-types'; + +export type { UserSelect, UserWithRelations } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + /** * Mutation hook for deleting a User - * + * * @example * \`\`\`tsx - * const { mutate, isPending } = useDeleteUserMutation(); - * - * mutate({ - * input: { - * id: 'value-to-delete', - * }, + * const { mutate, isPending } = useDeleteUserMutation({ + * select: { id: true }, * }); + * + * mutate({ id: 'value-to-delete' }); * \`\`\` */ -export function useDeleteUserMutation(options?: Omit, 'mutationFn'>) { +export function useDeleteUserMutation( + args?: { select?: DeepExact }, + options?: Omit } }, Error, { id: string }>, 'mutationFn'> +) { 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 ?? defaultSelect) as DeepExact }).unwrap(), onSuccess: (_, variables) => { - queryClient.removeQueries({ - queryKey: userKeys.detail(variables.input.id) - }); - queryClient.invalidateQueries({ - queryKey: userKeys.lists() - }); + queryClient.removeQueries({ queryKey: userKeys.detail(variables.id) }); + queryClient.invalidateQueries({ queryKey: userKeys.lists() }); }, - ...options + ...options, }); -}" +} +" `; exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mutation hook for table with relationships 1`] = ` @@ -822,59 +771,52 @@ exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mu * DO NOT EDIT - changes will be overwritten */ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -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 { useMutation, useQueryClient } from '@tanstack/react-query'; +import type { UseMutationOptions } from '@tanstack/react-query'; +import { getClient } from '../client'; +import { postKeys } from '../query-keys'; +import { postMutationKeys } from '../mutation-keys'; +import type { + PostSelect, + PostWithRelations, +} from '../../orm/input-types'; +import type { + DeepExact, + InferSelectResult, +} from '../../orm/select-types'; + +export type { PostSelect, PostWithRelations } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + /** * Mutation hook for deleting a Post - * + * * @example * \`\`\`tsx - * const { mutate, isPending } = useDeletePostMutation(); - * - * mutate({ - * input: { - * id: 'value-to-delete', - * }, + * const { mutate, isPending } = useDeletePostMutation({ + * select: { id: true }, * }); + * + * mutate({ id: 'value-to-delete' }); * \`\`\` */ -export function useDeletePostMutation(options?: Omit, 'mutationFn'>) { +export function useDeletePostMutation( + args?: { select?: DeepExact }, + options?: Omit } }, Error, { id: string }>, 'mutationFn'> +) { 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 ?? defaultSelect) as DeepExact }).unwrap(), onSuccess: (_, variables) => { - queryClient.removeQueries({ - queryKey: postKeys.detail(variables.input.id) - }); - queryClient.invalidateQueries({ - queryKey: postKeys.lists() - }); + queryClient.removeQueries({ queryKey: postKeys.detail(variables.id) }); + queryClient.invalidateQueries({ queryKey: postKeys.lists() }); }, - ...options + ...options, }); -}" +} +" `; exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mutation hook without centralized keys 1`] = ` @@ -884,55 +826,49 @@ exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mu * DO NOT EDIT - changes will be overwritten */ -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 { useMutation, useQueryClient } from '@tanstack/react-query'; +import type { UseMutationOptions } from '@tanstack/react-query'; +import { getClient } from '../client'; +import type { + UserSelect, + UserWithRelations, +} from '../../orm/input-types'; +import type { + DeepExact, + InferSelectResult, +} from '../../orm/select-types'; + +export type { UserSelect, UserWithRelations } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + /** * Mutation hook for deleting a User - * + * * @example * \`\`\`tsx - * const { mutate, isPending } = useDeleteUserMutation(); - * - * mutate({ - * input: { - * id: 'value-to-delete', - * }, + * const { mutate, isPending } = useDeleteUserMutation({ + * select: { id: true }, * }); + * + * mutate({ id: 'value-to-delete' }); * \`\`\` */ -export function useDeleteUserMutation(options?: Omit, 'mutationFn'>) { +export function useDeleteUserMutation( + args?: { select?: DeepExact }, + options?: Omit } }, Error, { id: string }>, 'mutationFn'> +) { const queryClient = useQueryClient(); return useMutation({ - mutationFn: (variables: DeleteUserMutationVariables) => execute(deleteUserMutationDocument, variables), + mutationFn: ({ id }: { id: string }) => getClient().user.delete({ where: { id }, select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), onSuccess: (_, variables) => { - queryClient.removeQueries({ - queryKey: ["user", "detail", variables.input.id] - }); - queryClient.invalidateQueries({ - queryKey: ["user", "list"] - }); + queryClient.removeQueries({ queryKey: ['user', 'detail', variables.id] }); + queryClient.invalidateQueries({ queryKey: ['user', 'list'] }); }, - ...options + ...options, }); -}" +} +" `; exports[`Mutation Hook Generators generateUpdateMutationHook generates update mutation hook for simple table 1`] = ` @@ -942,75 +878,53 @@ exports[`Mutation Hook Generators generateUpdateMutationHook generates update mu * DO NOT EDIT - changes will be overwritten */ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { User } from "../types"; -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 { useMutation, useQueryClient } from '@tanstack/react-query'; +import type { UseMutationOptions } from '@tanstack/react-query'; +import { getClient } from '../client'; +import { userKeys } from '../query-keys'; +import { userMutationKeys } from '../mutation-keys'; +import type { + UserSelect, + UserWithRelations, + UserPatch, +} from '../../orm/input-types'; +import type { + DeepExact, + InferSelectResult, +} from '../../orm/select-types'; + +export type { UserSelect, UserWithRelations, UserPatch } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + /** * 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({ + * select: { id: true, name: true }, * }); + * + * mutate({ id: 'value-here', patch: { name: 'Updated' } }); * \`\`\` */ -export function useUpdateUserMutation(options?: Omit, 'mutationFn'>) { +export function useUpdateUserMutation( + args?: { select?: DeepExact }, + options?: Omit } }, Error, { id: string; patch: UserPatch }>, 'mutationFn'> +) { 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 ?? defaultSelect) as DeepExact }).unwrap(), onSuccess: (_, variables) => { - queryClient.invalidateQueries({ - queryKey: userKeys.detail(variables.input.id) - }); - queryClient.invalidateQueries({ - queryKey: userKeys.lists() - }); + queryClient.invalidateQueries({ queryKey: userKeys.detail(variables.id) }); + queryClient.invalidateQueries({ queryKey: userKeys.lists() }); }, - ...options + ...options, }); -}" +} +" `; exports[`Mutation Hook Generators generateUpdateMutationHook generates update mutation hook for table with relationships 1`] = ` @@ -1020,80 +934,53 @@ exports[`Mutation Hook Generators generateUpdateMutationHook generates update mu * DO NOT EDIT - changes will be overwritten */ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { UseMutationOptions } from "@tanstack/react-query"; -import { execute } from "../client"; -import type { Post } from "../types"; -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 { useMutation, useQueryClient } from '@tanstack/react-query'; +import type { UseMutationOptions } from '@tanstack/react-query'; +import { getClient } from '../client'; +import { postKeys } from '../query-keys'; +import { postMutationKeys } from '../mutation-keys'; +import type { + PostSelect, + PostWithRelations, + PostPatch, +} from '../../orm/input-types'; +import type { + DeepExact, + InferSelectResult, +} from '../../orm/select-types'; + +export type { PostSelect, PostWithRelations, PostPatch } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + /** * 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({ + * select: { id: true, name: true }, * }); + * + * mutate({ id: 'value-here', patch: { name: 'Updated' } }); * \`\`\` */ -export function useUpdatePostMutation(options?: Omit, 'mutationFn'>) { +export function useUpdatePostMutation( + args?: { select?: DeepExact }, + options?: Omit } }, Error, { id: string; patch: PostPatch }>, 'mutationFn'> +) { 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 ?? defaultSelect) as DeepExact }).unwrap(), onSuccess: (_, variables) => { - queryClient.invalidateQueries({ - queryKey: postKeys.detail(variables.input.id) - }); - queryClient.invalidateQueries({ - queryKey: postKeys.lists() - }); + queryClient.invalidateQueries({ queryKey: postKeys.detail(variables.id) }); + queryClient.invalidateQueries({ queryKey: postKeys.lists() }); }, - ...options + ...options, }); -}" +} +" `; exports[`Mutation Hook Generators generateUpdateMutationHook generates update mutation hook without centralized keys 1`] = ` @@ -1103,72 +990,50 @@ exports[`Mutation Hook Generators generateUpdateMutationHook generates update mu * DO NOT EDIT - changes will be overwritten */ -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 { useMutation, useQueryClient } from '@tanstack/react-query'; +import type { UseMutationOptions } from '@tanstack/react-query'; +import { getClient } from '../client'; +import type { + UserSelect, + UserWithRelations, + UserPatch, +} from '../../orm/input-types'; +import type { + DeepExact, + InferSelectResult, +} from '../../orm/select-types'; + +export type { UserSelect, UserWithRelations, UserPatch } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + /** * 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({ + * select: { id: true, name: true }, * }); + * + * mutate({ id: 'value-here', patch: { name: 'Updated' } }); * \`\`\` */ -export function useUpdateUserMutation(options?: Omit, 'mutationFn'>) { +export function useUpdateUserMutation( + args?: { select?: DeepExact }, + options?: Omit } }, Error, { id: string; patch: UserPatch }>, 'mutationFn'> +) { 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 ?? defaultSelect) as DeepExact }).unwrap(), onSuccess: (_, variables) => { - queryClient.invalidateQueries({ - queryKey: ["user", "detail", variables.input.id] - }); - queryClient.invalidateQueries({ - queryKey: ["user", "list"] - }); + queryClient.invalidateQueries({ queryKey: ['user', 'detail', variables.id] }); + queryClient.invalidateQueries({ queryKey: ['user', 'list'] }); }, - ...options + ...options, }); -}" +} +" `; exports[`Query Hook Generators generateListQueryHook generates list query hook for simple table 1`] = ` @@ -1178,132 +1043,86 @@ exports[`Query Hook Generators generateListQueryHook generates list query hook f * DO NOT EDIT - changes will be overwritten */ -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 { 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 { useQuery } from '@tanstack/react-query'; +import type { UseQueryOptions, QueryClient } from '@tanstack/react-query'; +import { getClient } from '../client'; +import { userKeys } from '../query-keys'; +import type { + UserSelect, + UserWithRelations, + UserFilter, + UsersOrderBy, +} from '../../orm/input-types'; +import type { + FindManyArgs, + DeepExact, + InferSelectResult, + ConnectionResult, +} from '../../orm/select-types'; + +export type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + /** Query key factory - re-exported from query-keys.ts */ export const usersQueryKey = userKeys.list; + /** * Query hook for fetching User list - * + * * @example * \`\`\`tsx * const { data, isLoading } = useUsersQuery({ + * select: { id: true, name: true }, * first: 10, - * filter: { name: { equalTo: "example" } }, + * where: { name: { equalTo: "example" } }, * orderBy: ['CREATED_AT_DESC'], * }); * \`\`\` */ -export function useUsersQuery(variables?: UsersQueryVariables, options?: Omit, 'queryKey' | 'queryFn'>) { +export function useUsersQuery( + args?: FindManyArgs, UserFilter, UsersOrderBy>, + options?: Omit> }, Error>, 'queryKey' | 'queryFn'> +) { return useQuery({ - queryKey: userKeys.list(variables), - queryFn: () => execute(usersQueryDocument, variables), - ...options + queryKey: userKeys.list(args), + queryFn: () => getClient().user.findMany(args).unwrap(), + ...options, }); } + /** * Fetch User list without React hooks - * + * * @example * \`\`\`ts - * // Direct fetch - * const data = await fetchUsersQuery({ first: 10 }); - * - * // With QueryClient - * const data = await queryClient.fetchQuery({ - * queryKey: usersQueryKey(variables), - * queryFn: () => fetchUsersQuery(variables), - * }); + * const data = await fetchUsersQuery({ first: 10, select: { id: true } }); * \`\`\` */ -export async function fetchUsersQuery(variables?: UsersQueryVariables, options?: ExecuteOptions): Promise { - return execute(usersQueryDocument, variables, options); +export async function fetchUsersQuery( + args?: FindManyArgs, UserFilter, UsersOrderBy>, +) { + return getClient().user.findMany(args).unwrap(); } + /** * Prefetch User list for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchUsersQuery(queryClient, { first: 10 }); * \`\`\` */ -export async function prefetchUsersQuery(queryClient: QueryClient, variables?: UsersQueryVariables, options?: ExecuteOptions): Promise { +export async function prefetchUsersQuery( + queryClient: QueryClient, + args?: FindManyArgs, UserFilter, UsersOrderBy>, +): Promise { 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`] = ` @@ -1313,100 +1132,44 @@ exports[`Query Hook Generators generateListQueryHook generates list query hook f * DO NOT EDIT - changes will be overwritten */ -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 { 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 { useQuery } from '@tanstack/react-query'; +import type { UseQueryOptions, QueryClient } from '@tanstack/react-query'; +import { getClient } from '../client'; +import { postKeys } from '../query-keys'; +import type { PostScope } from '../query-keys'; +import type { + PostSelect, + PostWithRelations, + PostFilter, + PostsOrderBy, +} from '../../orm/input-types'; +import type { + FindManyArgs, + DeepExact, + InferSelectResult, + ConnectionResult, +} from '../../orm/select-types'; + +export type { PostSelect, PostWithRelations, PostFilter, PostsOrderBy } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + /** Query key factory - re-exported from query-keys.ts */ export const postsQueryKey = postKeys.list; + /** * Query hook for fetching Post list - * + * * @example * \`\`\`tsx * const { data, isLoading } = usePostsQuery({ + * select: { id: true, name: true }, * first: 10, - * filter: { name: { equalTo: "example" } }, + * where: { name: { equalTo: "example" } }, * orderBy: ['CREATED_AT_DESC'], * }); * \`\`\` - * + * * @example With scope for hierarchical cache invalidation * \`\`\`tsx * const { data } = usePostsQuery( @@ -1415,49 +1178,51 @@ export const postsQueryKey = postKeys.list; * ); * \`\`\` */ -export function usePostsQuery(variables?: PostsQueryVariables, options?: Omit, 'queryKey' | 'queryFn'> & { scope?: PostScope }) { - const { - scope, - ...queryOptions - } = options ?? {}; +export function usePostsQuery( + args?: FindManyArgs, PostFilter, PostsOrderBy>, + options?: Omit> }, Error>, 'queryKey' | 'queryFn'> & { scope?: PostScope } +) { + const { scope, ...queryOptions } = options ?? {}; return useQuery({ - queryKey: postKeys.list(variables, scope), - queryFn: () => execute(postsQueryDocument, variables), - ...queryOptions + queryKey: postKeys.list(args, scope), + queryFn: () => getClient().post.findMany(args).unwrap(), + ...queryOptions, }); } + /** * Fetch Post list without React hooks - * + * * @example * \`\`\`ts - * // Direct fetch - * const data = await fetchPostsQuery({ first: 10 }); - * - * // With QueryClient - * const data = await queryClient.fetchQuery({ - * queryKey: postsQueryKey(variables), - * queryFn: () => fetchPostsQuery(variables), - * }); + * const data = await fetchPostsQuery({ first: 10, select: { id: true } }); * \`\`\` */ -export async function fetchPostsQuery(variables?: PostsQueryVariables, options?: ExecuteOptions): Promise { - return execute(postsQueryDocument, variables, options); +export async function fetchPostsQuery( + args?: FindManyArgs, PostFilter, PostsOrderBy>, +) { + return getClient().post.findMany(args).unwrap(); } + /** * Prefetch Post list for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchPostsQuery(queryClient, { first: 10 }); * \`\`\` */ -export async function prefetchPostsQuery(queryClient: QueryClient, variables?: PostsQueryVariables, scope?: PostScope, options?: ExecuteOptions): Promise { +export async function prefetchPostsQuery( + queryClient: QueryClient, + args?: FindManyArgs, PostFilter, PostsOrderBy>, + scope?: PostScope, +): Promise { await queryClient.prefetchQuery({ - queryKey: postKeys.list(variables, scope), - queryFn: () => execute(postsQueryDocument, variables, options) + queryKey: postKeys.list(args, scope), + queryFn: () => getClient().post.findMany(args).unwrap(), }); -}" +} +" `; exports[`Query Hook Generators generateListQueryHook generates list query hook without centralized keys 1`] = ` @@ -1467,130 +1232,84 @@ exports[`Query Hook Generators generateListQueryHook generates list query hook w * DO NOT EDIT - changes will be overwritten */ -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 { useQuery } from '@tanstack/react-query'; +import type { UseQueryOptions, QueryClient } from '@tanstack/react-query'; +import { getClient } from '../client'; +import type { + UserSelect, + UserWithRelations, + UserFilter, + UsersOrderBy, +} from '../../orm/input-types'; +import type { + FindManyArgs, + DeepExact, + InferSelectResult, + ConnectionResult, +} from '../../orm/select-types'; + +export type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + +export const usersQueryKey = (variables?: FindManyArgs) => ['user', 'list', variables] as const; + /** * Query hook for fetching User list - * + * * @example * \`\`\`tsx * const { data, isLoading } = useUsersQuery({ + * select: { id: true, name: true }, * first: 10, - * filter: { name: { equalTo: "example" } }, + * where: { name: { equalTo: "example" } }, * orderBy: ['CREATED_AT_DESC'], * }); * \`\`\` */ -export function useUsersQuery(variables?: UsersQueryVariables, options?: Omit, 'queryKey' | 'queryFn'>) { +export function useUsersQuery( + args?: FindManyArgs, UserFilter, UsersOrderBy>, + options?: Omit> }, Error>, 'queryKey' | 'queryFn'> +) { return useQuery({ - queryKey: usersQueryKey(variables), - queryFn: () => execute(usersQueryDocument, variables), - ...options + queryKey: usersQueryKey(args), + queryFn: () => getClient().user.findMany(args).unwrap(), + ...options, }); } + /** * Fetch User list without React hooks - * + * * @example * \`\`\`ts - * // Direct fetch - * const data = await fetchUsersQuery({ first: 10 }); - * - * // With QueryClient - * const data = await queryClient.fetchQuery({ - * queryKey: usersQueryKey(variables), - * queryFn: () => fetchUsersQuery(variables), - * }); + * const data = await fetchUsersQuery({ first: 10, select: { id: true } }); * \`\`\` */ -export async function fetchUsersQuery(variables?: UsersQueryVariables, options?: ExecuteOptions): Promise { - return execute(usersQueryDocument, variables, options); +export async function fetchUsersQuery( + args?: FindManyArgs, UserFilter, UsersOrderBy>, +) { + return getClient().user.findMany(args).unwrap(); } + /** * Prefetch User list for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchUsersQuery(queryClient, { first: 10 }); * \`\`\` */ -export async function prefetchUsersQuery(queryClient: QueryClient, variables?: UsersQueryVariables, options?: ExecuteOptions): Promise { +export async function prefetchUsersQuery( + queryClient: QueryClient, + args?: FindManyArgs, UserFilter, UsersOrderBy>, +): Promise { 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`] = ` @@ -1600,71 +1319,80 @@ exports[`Query Hook Generators generateSingleQueryHook generates single query ho * DO NOT EDIT - changes will be overwritten */ -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 { 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 { useQuery } from '@tanstack/react-query'; +import type { UseQueryOptions, QueryClient } from '@tanstack/react-query'; +import { getClient } from '../client'; +import { userKeys } from '../query-keys'; +import type { + UserSelect, + UserWithRelations, +} from '../../orm/input-types'; +import type { + DeepExact, + InferSelectResult, +} from '../../orm/select-types'; + +export type { UserSelect, UserWithRelations } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + /** Query key factory - re-exported from query-keys.ts */ export const userQueryKey = userKeys.detail; + /** * Query hook for fetching a single User - * + * * @example * \`\`\`tsx - * const { data, isLoading } = useUserQuery({ id: 'some-id' }); + * const { data, isLoading } = useUserQuery({ + * id: 'some-id', + * select: { id: true, name: true }, + * }); * \`\`\` */ -export function useUserQuery(variables: UserQueryVariables, options?: Omit, 'queryKey' | 'queryFn'>) { +export function useUserQuery( + args: { id: string; select?: DeepExact }, + options?: Omit | null }, Error>, 'queryKey' | 'queryFn'> +) { return useQuery({ - queryKey: userKeys.detail(variables.id), - queryFn: () => execute(userQueryDocument, variables), - ...options + queryKey: userKeys.detail(args.id), + queryFn: () => getClient().user.findOne(args).unwrap(), + ...options, }); } + /** * Fetch a single User without React hooks - * + * * @example * \`\`\`ts - * const data = await fetchUserQuery({ id: 'some-id' }); + * const data = await fetchUserQuery({ id: 'some-id', select: { id: true } }); * \`\`\` */ -export async function fetchUserQuery(variables: UserQueryVariables, options?: ExecuteOptions): Promise { - return execute(userQueryDocument, variables, options); +export async function fetchUserQuery( + args: { id: string; select?: DeepExact }, +) { + return getClient().user.findOne(args).unwrap(); } + /** * Prefetch a single User for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchUserQuery(queryClient, { id: 'some-id' }); * \`\`\` */ -export async function prefetchUserQuery(queryClient: QueryClient, variables: UserQueryVariables, options?: ExecuteOptions): Promise { +export async function prefetchUserQuery( + queryClient: QueryClient, + args: { id: string; select?: DeepExact }, +): Promise { await queryClient.prefetchQuery({ - queryKey: userKeys.detail(variables.id), - queryFn: () => execute(userQueryDocument, variables, options) + queryKey: userKeys.detail(args.id), + queryFn: () => getClient().user.findOne(args).unwrap(), }); -}" +} +" `; exports[`Query Hook Generators generateSingleQueryHook generates single query hook for table with relationships 1`] = ` @@ -1674,42 +1402,38 @@ exports[`Query Hook Generators generateSingleQueryHook generates single query ho * DO NOT EDIT - changes will be overwritten */ -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 { 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 { useQuery } from '@tanstack/react-query'; +import type { UseQueryOptions, QueryClient } from '@tanstack/react-query'; +import { getClient } from '../client'; +import { postKeys } from '../query-keys'; +import type { PostScope } from '../query-keys'; +import type { + PostSelect, + PostWithRelations, +} from '../../orm/input-types'; +import type { + DeepExact, + InferSelectResult, +} from '../../orm/select-types'; + +export type { PostSelect, PostWithRelations } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + /** Query key factory - re-exported from query-keys.ts */ export const postQueryKey = postKeys.detail; + /** * Query hook for fetching a single Post - * + * * @example * \`\`\`tsx - * const { data, isLoading } = usePostQuery({ id: 'some-id' }); + * const { data, isLoading } = usePostQuery({ + * id: 'some-id', + * select: { id: true, name: true }, + * }); * \`\`\` - * + * * @example With scope for hierarchical cache invalidation * \`\`\`tsx * const { data } = usePostQuery( @@ -1718,42 +1442,51 @@ export const postQueryKey = postKeys.detail; * ); * \`\`\` */ -export function usePostQuery(variables: PostQueryVariables, options?: Omit, 'queryKey' | 'queryFn'> & { scope?: PostScope }) { - const { - scope, - ...queryOptions - } = options ?? {}; +export function usePostQuery( + args: { id: string; select?: DeepExact }, + options?: Omit | null }, Error>, 'queryKey' | 'queryFn'> & { scope?: PostScope } +) { + const { scope, ...queryOptions } = options ?? {}; return useQuery({ - queryKey: postKeys.detail(variables.id, scope), - queryFn: () => execute(postQueryDocument, variables), - ...queryOptions + queryKey: postKeys.detail(args.id, scope), + queryFn: () => getClient().post.findOne(args).unwrap(), + ...queryOptions, }); } + /** * Fetch a single Post without React hooks - * + * * @example * \`\`\`ts - * const data = await fetchPostQuery({ id: 'some-id' }); + * const data = await fetchPostQuery({ id: 'some-id', select: { id: true } }); * \`\`\` */ -export async function fetchPostQuery(variables: PostQueryVariables, options?: ExecuteOptions): Promise { - return execute(postQueryDocument, variables, options); +export async function fetchPostQuery( + args: { id: string; select?: DeepExact }, +) { + return getClient().post.findOne(args).unwrap(); } + /** * Prefetch a single Post for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchPostQuery(queryClient, { id: 'some-id' }); * \`\`\` */ -export async function prefetchPostQuery(queryClient: QueryClient, variables: PostQueryVariables, scope?: PostScope, options?: ExecuteOptions): Promise { +export async function prefetchPostQuery( + queryClient: QueryClient, + args: { id: string; select?: DeepExact }, + scope?: PostScope, +): Promise { await queryClient.prefetchQuery({ - queryKey: postKeys.detail(variables.id, scope), - queryFn: () => execute(postQueryDocument, variables, options) + queryKey: postKeys.detail(args.id, scope), + queryFn: () => getClient().post.findOne(args).unwrap(), }); -}" +} +" `; exports[`Query Hook Generators generateSingleQueryHook generates single query hook without centralized keys 1`] = ` @@ -1763,69 +1496,78 @@ exports[`Query Hook Generators generateSingleQueryHook generates single query ho * DO NOT EDIT - changes will be overwritten */ -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; -} -export const userQueryKey = (id: string) => ["user", "detail", id] as const; +import { useQuery } from '@tanstack/react-query'; +import type { UseQueryOptions, QueryClient } from '@tanstack/react-query'; +import { getClient } from '../client'; +import type { + UserSelect, + UserWithRelations, +} from '../../orm/input-types'; +import type { + DeepExact, + InferSelectResult, +} from '../../orm/select-types'; + +export type { UserSelect, UserWithRelations } from '../../orm/input-types'; + +const defaultSelect = { id: true } as const; + +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', + * select: { id: true, name: true }, + * }); * \`\`\` */ -export function useUserQuery(variables: UserQueryVariables, options?: Omit, 'queryKey' | 'queryFn'>) { +export function useUserQuery( + args: { id: string; select?: DeepExact }, + options?: Omit | null }, Error>, 'queryKey' | 'queryFn'> +) { return useQuery({ - queryKey: userQueryKey(variables.id), - queryFn: () => execute(userQueryDocument, variables), - ...options + queryKey: userQueryKey(args.id), + queryFn: () => getClient().user.findOne(args).unwrap(), + ...options, }); } + /** * Fetch a single User without React hooks - * + * * @example * \`\`\`ts - * const data = await fetchUserQuery({ id: 'some-id' }); + * const data = await fetchUserQuery({ id: 'some-id', select: { id: true } }); * \`\`\` */ -export async function fetchUserQuery(variables: UserQueryVariables, options?: ExecuteOptions): Promise { - return execute(userQueryDocument, variables, options); +export async function fetchUserQuery( + args: { id: string; select?: DeepExact }, +) { + return getClient().user.findOne(args).unwrap(); } + /** * Prefetch a single User for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchUserQuery(queryClient, { id: 'some-id' }); * \`\`\` */ -export async function prefetchUserQuery(queryClient: QueryClient, variables: UserQueryVariables, options?: ExecuteOptions): Promise { +export async function prefetchUserQuery( + queryClient: QueryClient, + args: { id: string; select?: DeepExact }, +): Promise { await queryClient.prefetchQuery({ - queryKey: userQueryKey(variables.id), - queryFn: () => execute(userQueryDocument, variables, options) + queryKey: userQueryKey(args.id), + queryFn: () => getClient().user.findOne(args).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..3bd0fbc02 100644 --- a/graphql/codegen/src/__tests__/codegen/client-generator.test.ts +++ b/graphql/codegen/src/__tests__/codegen/client-generator.test.ts @@ -4,12 +4,12 @@ * Tests the generated ORM client files: client.ts, query-builder.ts, select-types.ts, index.ts */ import { + generateCreateClientFile, generateOrmClientFile, generateQueryBuilderFile, - generateSelectTypesFile, - generateCreateClientFile, + generateSelectTypesFile } from '../../core/codegen/orm/client-generator'; -import type { CleanTable, CleanFieldType, CleanRelations } from '../../types/schema'; +import type { CleanFieldType, CleanRelations,CleanTable } from '../../types/schema'; // ============================================================================ // Test Fixtures @@ -17,14 +17,14 @@ import type { CleanTable, CleanFieldType, CleanRelations } from '../../types/sch const fieldTypes = { uuid: { gqlType: 'UUID', isArray: false } as CleanFieldType, - string: { gqlType: 'String', isArray: false } as CleanFieldType, + string: { gqlType: 'String', isArray: false } as CleanFieldType }; const emptyRelations: CleanRelations = { belongsTo: [], hasOne: [], hasMany: [], - manyToMany: [], + manyToMany: [] }; function createTable(partial: Partial & { name: string }): CleanTable { @@ -34,7 +34,7 @@ function createTable(partial: Partial & { name: string }): CleanTabl relations: partial.relations ?? emptyRelations, query: partial.query, inflection: partial.inflection, - constraints: partial.constraints, + constraints: partial.constraints }; } @@ -91,13 +91,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' } }), 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' } + }) ]; const result = generateCreateClientFile(tables, false, false); @@ -114,8 +114,8 @@ 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' } + }) ]; const result = generateCreateClientFile(tables, true, true); @@ -123,8 +123,8 @@ 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..241a7ae69 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,15 @@ * 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'; // ============================================================================ @@ -32,7 +32,7 @@ const fieldTypes = { json: { gqlType: 'JSON', isArray: false } as CleanFieldType, bigint: { gqlType: 'BigInt', isArray: false } as CleanFieldType, stringArray: { gqlType: 'String', isArray: true } as CleanFieldType, - intArray: { gqlType: 'Int', isArray: true } as CleanFieldType, + intArray: { gqlType: 'Int', isArray: true } as CleanFieldType }; // ============================================================================ @@ -43,7 +43,7 @@ const emptyRelations: CleanRelations = { belongsTo: [], hasOne: [], hasMany: [], - manyToMany: [], + manyToMany: [] }; function createTable(partial: Partial & { name: string }): CleanTable { @@ -53,7 +53,7 @@ function createTable(partial: Partial & { name: string }): CleanTabl relations: partial.relations ?? emptyRelations, query: partial.query, inflection: partial.inflection, - constraints: partial.constraints, + constraints: partial.constraints }; } @@ -89,15 +89,15 @@ const userTable = createTable({ { name: 'age', type: fieldTypes.int }, { name: 'isActive', type: fieldTypes.boolean }, { name: 'createdAt', type: fieldTypes.datetime }, - { name: 'metadata', type: fieldTypes.json }, + { name: 'metadata', type: fieldTypes.json } ], query: { all: 'users', one: 'user', create: 'createUser', update: 'updateUser', - delete: 'deleteUser', - }, + delete: 'deleteUser' + } }); /** @@ -111,7 +111,7 @@ const postTable = createTable({ { name: 'content', type: fieldTypes.string }, { name: 'authorId', type: fieldTypes.uuid }, { name: 'publishedAt', type: fieldTypes.datetime }, - { name: 'tags', type: fieldTypes.stringArray }, + { name: 'tags', type: fieldTypes.stringArray } ], relations: { belongsTo: [ @@ -120,8 +120,8 @@ const postTable = createTable({ isUnique: false, referencesTable: 'User', type: null, - keys: [{ name: 'authorId', type: fieldTypes.uuid }], - }, + keys: [{ name: 'authorId', type: fieldTypes.uuid }] + } ], hasOne: [], hasMany: [ @@ -130,18 +130,18 @@ const postTable = createTable({ isUnique: false, referencedByTable: 'Comment', type: null, - keys: [], - }, + keys: [] + } ], - manyToMany: [], + manyToMany: [] }, query: { all: 'posts', one: 'post', create: 'createPost', update: 'updatePost', - delete: 'deletePost', - }, + delete: 'deletePost' + } }); /** @@ -154,7 +154,7 @@ const commentTable = createTable({ { name: 'body', type: fieldTypes.string }, { name: 'postId', type: fieldTypes.uuid }, { name: 'authorId', type: fieldTypes.uuid }, - { name: 'createdAt', type: fieldTypes.datetime }, + { name: 'createdAt', type: fieldTypes.datetime } ], relations: { belongsTo: [ @@ -163,27 +163,27 @@ const commentTable = createTable({ isUnique: false, referencesTable: 'Post', type: null, - keys: [], + keys: [] }, { fieldName: 'author', isUnique: false, referencesTable: 'User', type: null, - keys: [], - }, + keys: [] + } ], hasOne: [], hasMany: [], - manyToMany: [], + manyToMany: [] }, query: { all: 'comments', one: 'comment', create: 'createComment', update: 'updateComment', - delete: 'deleteComment', - }, + delete: 'deleteComment' + } }); /** @@ -200,18 +200,18 @@ const userTableWithRelations = createTable({ isUnique: false, referencedByTable: 'Post', type: null, - keys: [], + keys: [] }, { fieldName: 'comments', isUnique: false, referencedByTable: 'Comment', type: null, - keys: [], - }, + keys: [] + } ], - manyToMany: [], - }, + manyToMany: [] + } }); /** @@ -222,7 +222,7 @@ const categoryTable = createTable({ fields: [ { name: 'id', type: fieldTypes.uuid }, { name: 'name', type: fieldTypes.string }, - { name: 'slug', type: fieldTypes.string }, + { name: 'slug', type: fieldTypes.string } ], relations: { belongsTo: [], @@ -233,17 +233,17 @@ const categoryTable = createTable({ fieldName: 'posts', rightTable: 'Post', junctionTable: 'PostCategory', - type: null, - }, - ], + type: null + } + ] }, query: { all: 'categories', one: 'category', create: 'createCategory', update: 'updateCategory', - delete: 'deleteCategory', - }, + delete: 'deleteCategory' + } }); /** @@ -255,7 +255,7 @@ const profileTable = createTable({ { name: 'id', type: fieldTypes.uuid }, { name: 'bio', type: fieldTypes.string }, { name: 'userId', type: fieldTypes.uuid }, - { name: 'avatarUrl', type: fieldTypes.string }, + { name: 'avatarUrl', type: fieldTypes.string } ], relations: { belongsTo: [ @@ -264,20 +264,20 @@ const profileTable = createTable({ isUnique: true, referencesTable: 'User', type: null, - keys: [], - }, + keys: [] + } ], hasOne: [], hasMany: [], - manyToMany: [], + manyToMany: [] }, query: { all: 'profiles', one: 'profile', create: 'createProfile', update: 'updateProfile', - delete: 'deleteProfile', - }, + delete: 'deleteProfile' + } }); // User with hasOne to profile @@ -291,8 +291,8 @@ const userTableWithProfile = createTable({ isUnique: true, referencedByTable: 'Profile', type: null, - keys: [], - }, + keys: [] + } ], hasMany: [ { @@ -300,11 +300,11 @@ const userTableWithProfile = createTable({ isUnique: false, referencedByTable: 'Post', type: null, - keys: [], - }, + keys: [] + } ], - manyToMany: [], - }, + manyToMany: [] + } }); // ============================================================================ @@ -318,8 +318,8 @@ const sampleTypeRegistry = createTypeRegistry({ inputFields: [ { name: 'email', type: createNonNull(createTypeRef('SCALAR', 'String')) }, { name: 'password', type: createNonNull(createTypeRef('SCALAR', 'String')) }, - { name: 'rememberMe', type: createTypeRef('SCALAR', 'Boolean') }, - ], + { name: 'rememberMe', type: createTypeRef('SCALAR', 'Boolean') } + ] }, RegisterInput: { kind: 'INPUT_OBJECT', @@ -327,13 +327,13 @@ const sampleTypeRegistry = createTypeRegistry({ inputFields: [ { name: 'email', type: createNonNull(createTypeRef('SCALAR', 'String')) }, { name: 'password', type: createNonNull(createTypeRef('SCALAR', 'String')) }, - { name: 'name', type: createTypeRef('SCALAR', 'String') }, - ], + { name: 'name', type: createTypeRef('SCALAR', 'String') } + ] }, UserRole: { kind: 'ENUM', name: 'UserRole', - enumValues: ['ADMIN', 'USER', 'GUEST'], + enumValues: ['ADMIN', 'USER', 'GUEST'] }, LoginPayload: { kind: 'OBJECT', @@ -341,9 +341,9 @@ const sampleTypeRegistry = createTypeRegistry({ fields: [ { name: 'token', type: createTypeRef('SCALAR', 'String') }, { name: 'user', type: createTypeRef('OBJECT', 'User') }, - { name: 'expiresAt', type: createTypeRef('SCALAR', 'Datetime') }, - ], - }, + { name: 'expiresAt', type: createTypeRef('SCALAR', 'Datetime') } + ] + } }); // ============================================================================ @@ -646,14 +646,14 @@ describe('collectInputTypeNames', () => { const operations = [ { args: [ - { name: 'input', type: createNonNull(createTypeRef('INPUT_OBJECT', 'LoginInput')) }, - ] as CleanArgument[], + { name: 'input', type: createNonNull(createTypeRef('INPUT_OBJECT', 'LoginInput')) } + ] as CleanArgument[] }, { args: [ - { name: 'data', type: createTypeRef('INPUT_OBJECT', 'RegisterInput') }, - ] as CleanArgument[], - }, + { name: 'data', type: createTypeRef('INPUT_OBJECT', 'RegisterInput') } + ] as CleanArgument[] + } ]; const result = collectInputTypeNames(operations); @@ -666,9 +666,9 @@ describe('collectInputTypeNames', () => { const operations = [ { args: [ - { name: 'filter', type: createTypeRef('INPUT_OBJECT', 'UserFilter') }, - ] as CleanArgument[], - }, + { name: 'filter', type: createTypeRef('INPUT_OBJECT', 'UserFilter') } + ] as CleanArgument[] + } ]; const result = collectInputTypeNames(operations); @@ -681,7 +681,7 @@ describe('collectPayloadTypeNames', () => { it('collects Payload type names from operations', () => { const operations = [ { returnType: createTypeRef('OBJECT', 'LoginPayload') }, - { returnType: createTypeRef('OBJECT', 'RegisterPayload') }, + { returnType: createTypeRef('OBJECT', 'RegisterPayload') } ]; const result = collectPayloadTypeNames(operations); @@ -690,14 +690,14 @@ describe('collectPayloadTypeNames', () => { expect(result.has('RegisterPayload')).toBe(true); }); - it('excludes Connection types', () => { + it('includes Connection types', () => { const operations = [ - { returnType: createTypeRef('OBJECT', 'UsersConnection') }, + { returnType: createTypeRef('OBJECT', 'UsersConnection') } ]; const result = collectPayloadTypeNames(operations); - expect(result.has('UsersConnection')).toBe(false); + expect(result.has('UsersConnection')).toBe(true); }); }); @@ -717,7 +717,7 @@ describe('edge cases', () => { it('handles table with only id field', () => { const minimalTable = createTable({ name: 'Minimal', - fields: [{ name: 'id', type: fieldTypes.uuid }], + fields: [{ name: 'id', type: fieldTypes.uuid }] }); const result = generateInputTypesFile(new Map(), new Set(), [minimalTable]); diff --git a/graphql/codegen/src/__tests__/codegen/model-generator.test.ts b/graphql/codegen/src/__tests__/codegen/model-generator.test.ts index 1a27b9062..86de98981 100644 --- a/graphql/codegen/src/__tests__/codegen/model-generator.test.ts +++ b/graphql/codegen/src/__tests__/codegen/model-generator.test.ts @@ -4,7 +4,7 @@ * 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 @@ -15,14 +15,14 @@ const fieldTypes = { string: { gqlType: 'String', isArray: false } as CleanFieldType, int: { gqlType: 'Int', isArray: false } as CleanFieldType, boolean: { gqlType: 'Boolean', isArray: false } as CleanFieldType, - datetime: { gqlType: 'Datetime', isArray: false } as CleanFieldType, + datetime: { gqlType: 'Datetime', isArray: false } as CleanFieldType }; const emptyRelations: CleanRelations = { belongsTo: [], hasOne: [], hasMany: [], - manyToMany: [], + manyToMany: [] }; function createTable(partial: Partial & { name: string }): CleanTable { @@ -32,7 +32,7 @@ function createTable(partial: Partial & { name: string }): CleanTabl relations: partial.relations ?? emptyRelations, query: partial.query, inflection: partial.inflection, - constraints: partial.constraints, + constraints: partial.constraints }; } @@ -49,15 +49,15 @@ describe('model-generator', () => { { name: 'email', type: fieldTypes.string }, { name: 'name', type: fieldTypes.string }, { name: 'isActive', type: fieldTypes.boolean }, - { name: 'createdAt', type: fieldTypes.datetime }, + { name: 'createdAt', type: fieldTypes.datetime } ], query: { all: 'users', one: 'user', create: 'createUser', update: 'updateUser', - delete: 'deleteUser', - }, + delete: 'deleteUser' + } }); const result = generateModelFile(table, false); @@ -73,15 +73,15 @@ describe('model-generator', () => { fields: [ { name: 'id', type: fieldTypes.uuid }, { name: 'action', type: fieldTypes.string }, - { name: 'timestamp', type: fieldTypes.datetime }, + { name: 'timestamp', type: fieldTypes.datetime } ], query: { all: 'auditLogs', one: 'auditLog', create: 'createAuditLog', update: undefined, - delete: undefined, - }, + delete: undefined + } }); const result = generateModelFile(table, false); @@ -99,15 +99,15 @@ describe('model-generator', () => { name: 'Organization', fields: [ { name: 'id', type: fieldTypes.uuid }, - { name: 'name', type: fieldTypes.string }, + { name: 'name', type: fieldTypes.string } ], query: { all: 'allOrganizations', one: 'organizationById', create: 'registerOrganization', update: 'modifyOrganization', - delete: 'removeOrganization', - }, + delete: 'removeOrganization' + } }); const result = generateModelFile(table, false); @@ -125,15 +125,15 @@ describe('model-generator', () => { fields: [ { name: 'id', type: fieldTypes.uuid }, { name: 'name', type: fieldTypes.string }, - { name: 'price', type: fieldTypes.int }, + { name: 'price', type: fieldTypes.int } ], query: { all: 'products', one: 'product', create: 'createProduct', update: 'updateProduct', - delete: 'deleteProduct', - }, + delete: 'deleteProduct' + } }); const result = generateModelFile(table, false); diff --git a/graphql/codegen/src/__tests__/codegen/query-builder.test.ts b/graphql/codegen/src/__tests__/codegen/query-builder.test.ts index b91c420fc..7c0d3b599 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) @@ -16,7 +16,7 @@ function buildConnectionSelections(nodeSelections: FieldNode[]): FieldNode[] { return [ t.field({ name: 'nodes', - selectionSet: t.selectionSet({ selections: nodeSelections }), + selectionSet: t.selectionSet({ selections: nodeSelections }) }), t.field({ name: 'totalCount' }), t.field({ @@ -26,10 +26,10 @@ function buildConnectionSelections(nodeSelections: FieldNode[]): FieldNode[] { t.field({ name: 'hasNextPage' }), t.field({ name: 'hasPreviousPage' }), t.field({ name: 'startCursor' }), - t.field({ name: 'endCursor' }), - ], - }), - }), + t.field({ name: 'endCursor' }) + ] + }) + }) ]; } @@ -43,13 +43,13 @@ function addVariable( definitions.push( t.variableDefinition({ variable: t.variable({ name: spec.varName }), - type: parseType(spec.typeName), + type: parseType(spec.typeName) }) ); args.push( t.argument({ name: spec.argName ?? spec.varName, - value: t.variable({ name: spec.varName }), + value: t.variable({ name: spec.varName }) }) ); variables[spec.varName] = spec.value; @@ -66,7 +66,7 @@ function buildSelections(select: Record | undefined): FieldNode fields.push( t.field({ name: key, - selectionSet: t.selectionSet({ selections: buildSelections(nested.select) }), + selectionSet: t.selectionSet({ selections: buildSelections(nested.select) }) }) ); } @@ -104,12 +104,12 @@ function buildFindManyDocument( t.field({ name: queryField, args: queryArgs.length ? queryArgs : undefined, - selectionSet: t.selectionSet({ selections: buildConnectionSelections(selections) }), - }), - ], - }), - }), - ], + selectionSet: t.selectionSet({ selections: buildConnectionSelections(selections) }) + }) + ] + }) + }) + ] }); return { document: print(document), variables }; } @@ -130,8 +130,8 @@ function buildMutationDocument( variableDefinitions: [ t.variableDefinition({ variable: t.variable({ name: 'input' }), - type: parseType(inputTypeName + '!'), - }), + type: parseType(inputTypeName + '!') + }) ], selectionSet: t.selectionSet({ selections: [ @@ -142,15 +142,15 @@ function buildMutationDocument( selections: [ t.field({ name: entityField, - selectionSet: t.selectionSet({ selections }), - }), - ], - }), - }), - ], - }), - }), - ], + selectionSet: t.selectionSet({ selections }) + }) + ] + }) + }) + ] + }) + }) + ] }) ); } @@ -166,7 +166,7 @@ describe('query-builder', () => { id: true, name: true, ignored: false, - profile: { select: { bio: true } }, + profile: { select: { bio: true } } }); expect(result).toHaveLength(3); @@ -199,7 +199,7 @@ describe('query-builder', () => { expect(variables).toEqual({ where: { status: { equalTo: 'active' } }, first: 10, - orderBy: ['NAME_ASC'], + orderBy: ['NAME_ASC'] }); }); }); 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..ad96c2697 100644 --- a/graphql/codegen/src/__tests__/codegen/query-keys-factory.test.ts +++ b/graphql/codegen/src/__tests__/codegen/query-keys-factory.test.ts @@ -6,24 +6,24 @@ * - 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, string: { gqlType: 'String', isArray: false } as CleanFieldType, int: { gqlType: 'Int', isArray: false } as CleanFieldType, - datetime: { gqlType: 'Datetime', isArray: false } as CleanFieldType, + datetime: { gqlType: 'Datetime', isArray: false } as CleanFieldType }; const emptyRelations: CleanRelations = { belongsTo: [], hasOne: [], hasMany: [], - manyToMany: [], + manyToMany: [] }; function createTable(partial: Partial & { name: string }): CleanTable { @@ -33,7 +33,7 @@ function createTable(partial: Partial & { name: string }): CleanTabl relations: partial.relations ?? emptyRelations, query: partial.query, inflection: partial.inflection, - constraints: partial.constraints, + constraints: partial.constraints }; } @@ -47,15 +47,15 @@ const simpleUserTable = createTable({ { name: 'id', type: fieldTypes.uuid }, { name: 'email', type: fieldTypes.string }, { name: 'name', type: fieldTypes.string }, - { name: 'createdAt', type: fieldTypes.datetime }, + { name: 'createdAt', type: fieldTypes.datetime } ], query: { all: 'users', one: 'user', create: 'createUser', update: 'updateUser', - delete: 'deleteUser', - }, + delete: 'deleteUser' + } }); const postTable = createTable({ @@ -65,15 +65,15 @@ const postTable = createTable({ { name: 'title', type: fieldTypes.string }, { name: 'content', type: fieldTypes.string }, { name: 'authorId', type: fieldTypes.uuid }, - { name: 'createdAt', type: fieldTypes.datetime }, + { name: 'createdAt', type: fieldTypes.datetime } ], query: { all: 'posts', one: 'post', create: 'createPost', update: 'updatePost', - delete: 'deletePost', - }, + delete: 'deletePost' + } }); const organizationTable = createTable({ @@ -81,15 +81,15 @@ const organizationTable = createTable({ fields: [ { name: 'id', type: fieldTypes.uuid }, { name: 'name', type: fieldTypes.string }, - { name: 'slug', type: fieldTypes.string }, + { name: 'slug', type: fieldTypes.string } ], query: { all: 'organizations', one: 'organization', create: 'createOrganization', update: 'updateOrganization', - delete: 'deleteOrganization', - }, + delete: 'deleteOrganization' + } }); const databaseTable = createTable({ @@ -97,15 +97,15 @@ const databaseTable = createTable({ fields: [ { name: 'id', type: fieldTypes.uuid }, { name: 'name', type: fieldTypes.string }, - { name: 'organizationId', type: fieldTypes.uuid }, + { name: 'organizationId', type: fieldTypes.uuid } ], query: { all: 'databases', one: 'database', create: 'createDatabase', update: 'updateDatabase', - delete: 'deleteDatabase', - }, + delete: 'deleteDatabase' + } }); const tableEntityTable = createTable({ @@ -113,15 +113,15 @@ const tableEntityTable = createTable({ fields: [ { name: 'id', type: fieldTypes.uuid }, { name: 'name', type: fieldTypes.string }, - { name: 'databaseId', type: fieldTypes.uuid }, + { name: 'databaseId', type: fieldTypes.uuid } ], query: { all: 'tables', one: 'table', create: 'createTable', update: 'updateTable', - delete: 'deleteTable', - }, + delete: 'deleteTable' + } }); const fieldTable = createTable({ @@ -130,15 +130,15 @@ const fieldTable = createTable({ { name: 'id', type: fieldTypes.uuid }, { name: 'name', type: fieldTypes.string }, { name: 'tableId', type: fieldTypes.uuid }, - { name: 'type', type: fieldTypes.string }, + { name: 'type', type: fieldTypes.string } ], query: { all: 'fields', one: 'field', create: 'createField', update: 'updateField', - delete: 'deleteField', - }, + delete: 'deleteField' + } }); const simpleConfig: QueryKeyConfig = { @@ -146,17 +146,17 @@ const simpleConfig: QueryKeyConfig = { relationships: {}, generateScopedKeys: true, generateCascadeHelpers: true, - generateMutationKeys: true, + generateMutationKeys: true }; const simpleRelationships: Record = { - post: { parent: 'User', foreignKey: 'authorId' }, + post: { parent: 'User', foreignKey: 'authorId' } }; const hierarchicalRelationships: Record = { database: { parent: 'Organization', foreignKey: 'organizationId' }, table: { parent: 'Database', foreignKey: 'databaseId', ancestors: ['organization'] }, - field: { parent: 'Table', foreignKey: 'tableId', ancestors: ['database', 'organization'] }, + field: { parent: 'Table', foreignKey: 'tableId', ancestors: ['database', 'organization'] } }; const sampleCustomQueries: CleanOperation[] = [ @@ -165,18 +165,18 @@ const sampleCustomQueries: CleanOperation[] = [ kind: 'query', args: [], returnType: createTypeRef('OBJECT', 'User'), - description: 'Get the current authenticated user', + description: 'Get the current authenticated user' }, { name: 'searchUsers', kind: 'query', args: [ { name: 'query', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) }, - { name: 'limit', type: createTypeRef('SCALAR', 'Int') }, + { name: 'limit', type: createTypeRef('SCALAR', 'Int') } ], returnType: createTypeRef('LIST', null, createTypeRef('OBJECT', 'User')), - description: 'Search users by name or email', - }, + description: 'Search users by name or email' + } ]; const sampleCustomMutations: CleanOperation[] = [ @@ -185,18 +185,18 @@ const sampleCustomMutations: CleanOperation[] = [ kind: 'mutation', args: [ { name: 'email', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) }, - { name: 'password', 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', + description: 'Authenticate user' }, { name: 'logout', kind: 'mutation', args: [], returnType: createTypeRef('OBJECT', 'LogoutPayload'), - description: 'Log out current user', - }, + description: 'Log out current user' + } ]; describe('generateQueryKeysFile', () => { @@ -204,7 +204,7 @@ describe('generateQueryKeysFile', () => { const result = generateQueryKeysFile({ tables: [simpleUserTable], customQueries: [], - config: simpleConfig, + config: simpleConfig }); expect(result.fileName).toBe('query-keys.ts'); expect(result.content).toMatchSnapshot(); @@ -214,7 +214,7 @@ describe('generateQueryKeysFile', () => { const result = generateQueryKeysFile({ tables: [simpleUserTable, postTable], customQueries: [], - config: simpleConfig, + config: simpleConfig }); expect(result.content).toMatchSnapshot(); }); @@ -225,8 +225,8 @@ describe('generateQueryKeysFile', () => { customQueries: [], config: { ...simpleConfig, - relationships: simpleRelationships, - }, + relationships: simpleRelationships + } }); expect(result.content).toMatchSnapshot(); }); @@ -237,8 +237,8 @@ describe('generateQueryKeysFile', () => { customQueries: [], config: { ...simpleConfig, - relationships: hierarchicalRelationships, - }, + relationships: hierarchicalRelationships + } }); expect(result.content).toMatchSnapshot(); }); @@ -247,7 +247,7 @@ describe('generateQueryKeysFile', () => { const result = generateQueryKeysFile({ tables: [simpleUserTable], customQueries: sampleCustomQueries, - config: simpleConfig, + config: simpleConfig }); expect(result.content).toMatchSnapshot(); }); @@ -259,8 +259,8 @@ describe('generateQueryKeysFile', () => { config: { ...simpleConfig, relationships: simpleRelationships, - generateScopedKeys: false, - }, + generateScopedKeys: false + } }); expect(result.content).toMatchSnapshot(); }); @@ -271,7 +271,7 @@ describe('generateMutationKeysFile', () => { const result = generateMutationKeysFile({ tables: [simpleUserTable], customMutations: [], - config: simpleConfig, + config: simpleConfig }); expect(result.fileName).toBe('mutation-keys.ts'); expect(result.content).toMatchSnapshot(); @@ -281,7 +281,7 @@ describe('generateMutationKeysFile', () => { const result = generateMutationKeysFile({ tables: [simpleUserTable, postTable], customMutations: [], - config: simpleConfig, + config: simpleConfig }); expect(result.content).toMatchSnapshot(); }); @@ -292,8 +292,8 @@ describe('generateMutationKeysFile', () => { customMutations: [], config: { ...simpleConfig, - relationships: simpleRelationships, - }, + relationships: simpleRelationships + } }); expect(result.content).toMatchSnapshot(); }); @@ -302,7 +302,7 @@ describe('generateMutationKeysFile', () => { const result = generateMutationKeysFile({ tables: [simpleUserTable], customMutations: sampleCustomMutations, - config: simpleConfig, + config: simpleConfig }); expect(result.content).toMatchSnapshot(); }); @@ -313,8 +313,8 @@ describe('generateMutationKeysFile', () => { customMutations: [], config: { ...simpleConfig, - relationships: hierarchicalRelationships, - }, + relationships: hierarchicalRelationships + } }); expect(result.content).toMatchSnapshot(); }); @@ -324,7 +324,7 @@ describe('generateInvalidationFile', () => { it('generates invalidation helpers for a single table without relationships', () => { const result = generateInvalidationFile({ tables: [simpleUserTable], - config: simpleConfig, + config: simpleConfig }); expect(result.fileName).toBe('invalidation.ts'); expect(result.content).toMatchSnapshot(); @@ -333,7 +333,7 @@ describe('generateInvalidationFile', () => { it('generates invalidation helpers for multiple tables', () => { const result = generateInvalidationFile({ tables: [simpleUserTable, postTable], - config: simpleConfig, + config: simpleConfig }); expect(result.content).toMatchSnapshot(); }); @@ -343,8 +343,8 @@ describe('generateInvalidationFile', () => { tables: [simpleUserTable, postTable], config: { ...simpleConfig, - relationships: simpleRelationships, - }, + relationships: simpleRelationships + } }); expect(result.content).toMatchSnapshot(); }); @@ -354,8 +354,8 @@ describe('generateInvalidationFile', () => { tables: [organizationTable, databaseTable, tableEntityTable, fieldTable], config: { ...simpleConfig, - relationships: hierarchicalRelationships, - }, + relationships: hierarchicalRelationships + } }); expect(result.content).toMatchSnapshot(); }); @@ -366,8 +366,8 @@ describe('generateInvalidationFile', () => { config: { ...simpleConfig, relationships: simpleRelationships, - generateCascadeHelpers: false, - }, + generateCascadeHelpers: false + } }); expect(result.content).toMatchSnapshot(); }); 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..a8a187295 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,26 @@ * - 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 = { @@ -36,14 +36,14 @@ const fieldTypes = { string: { gqlType: 'String', isArray: false } as CleanFieldType, int: { gqlType: 'Int', isArray: false } as CleanFieldType, datetime: { gqlType: 'Datetime', isArray: false } as CleanFieldType, - boolean: { gqlType: 'Boolean', isArray: false } as CleanFieldType, + boolean: { gqlType: 'Boolean', isArray: false } as CleanFieldType }; const emptyRelations: CleanRelations = { belongsTo: [], hasOne: [], hasMany: [], - manyToMany: [], + manyToMany: [] }; function createTable(partial: Partial & { name: string }): CleanTable { @@ -53,7 +53,7 @@ function createTable(partial: Partial & { name: string }): CleanTabl relations: partial.relations ?? emptyRelations, query: partial.query, inflection: partial.inflection, - constraints: partial.constraints, + constraints: partial.constraints }; } @@ -67,15 +67,15 @@ const simpleUserTable = createTable({ { name: 'id', type: fieldTypes.uuid }, { name: 'email', type: fieldTypes.string }, { name: 'name', type: fieldTypes.string }, - { name: 'createdAt', type: fieldTypes.datetime }, + { name: 'createdAt', type: fieldTypes.datetime } ], query: { all: 'users', one: 'user', create: 'createUser', update: 'updateUser', - delete: 'deleteUser', - }, + delete: 'deleteUser' + } }); const postTable = createTable({ @@ -86,15 +86,15 @@ const postTable = createTable({ { name: 'content', type: fieldTypes.string }, { name: 'authorId', type: fieldTypes.uuid }, { name: 'published', type: fieldTypes.boolean }, - { name: 'createdAt', type: fieldTypes.datetime }, + { name: 'createdAt', type: fieldTypes.datetime } ], query: { all: 'posts', one: 'post', create: 'createPost', update: 'updatePost', - delete: 'deletePost', - }, + delete: 'deletePost' + } }); const simpleCustomQueries: CleanOperation[] = [ @@ -103,18 +103,18 @@ const simpleCustomQueries: CleanOperation[] = [ kind: 'query', args: [], returnType: createTypeRef('OBJECT', 'User'), - description: 'Get the current authenticated user', + description: 'Get the current authenticated user' }, { name: 'searchUsers', kind: 'query', args: [ { name: 'query', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) }, - { name: 'limit', type: createTypeRef('SCALAR', 'Int') }, + { name: 'limit', type: createTypeRef('SCALAR', 'Int') } ], returnType: createTypeRef('LIST', null, createTypeRef('OBJECT', 'User')), - description: 'Search users by name or email', - }, + description: 'Search users by name or email' + } ]; const simpleCustomMutations: CleanOperation[] = [ @@ -123,27 +123,27 @@ const simpleCustomMutations: CleanOperation[] = [ kind: 'mutation', args: [ { name: 'email', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) }, - { name: 'password', 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', + description: 'Authenticate user' }, { name: 'logout', kind: 'mutation', args: [], returnType: createTypeRef('OBJECT', 'LogoutPayload'), - description: 'Log out current user', + description: 'Log out current user' }, { 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', - }, + description: 'Register a new user' + } ]; function createTypeRegistry(): TypeRegistry { @@ -154,16 +154,16 @@ function createTypeRegistry(): TypeRegistry { name: 'LoginPayload', fields: [ { name: 'token', type: createTypeRef('SCALAR', 'String') }, - { name: 'user', type: createTypeRef('OBJECT', 'User') }, - ], + { name: 'user', type: createTypeRef('OBJECT', 'User') } + ] } as ResolvedType); registry.set('LogoutPayload', { kind: 'OBJECT', name: 'LogoutPayload', fields: [ - { name: 'success', type: createTypeRef('SCALAR', 'Boolean') }, - ], + { name: 'success', type: createTypeRef('SCALAR', 'Boolean') } + ] } as ResolvedType); registry.set('RegisterPayload', { @@ -171,8 +171,8 @@ function createTypeRegistry(): TypeRegistry { name: 'RegisterPayload', fields: [ { name: 'token', type: createTypeRef('SCALAR', 'String') }, - { name: 'user', type: createTypeRef('OBJECT', 'User') }, - ], + { name: 'user', type: createTypeRef('OBJECT', 'User') } + ] } as ResolvedType); registry.set('RegisterInput', { @@ -181,22 +181,22 @@ function createTypeRegistry(): TypeRegistry { inputFields: [ { 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') }, - ], + { name: 'name', type: createTypeRef('SCALAR', 'String') } + ] } as ResolvedType); registry.set('UserRole', { kind: 'ENUM', name: 'UserRole', - enumValues: ['ADMIN', 'USER', 'GUEST'], + enumValues: ['ADMIN', 'USER', 'GUEST'] } as ResolvedType); registry.set('Query', { kind: 'OBJECT', name: 'Query', fields: [ - { name: 'currentUser', type: createTypeRef('OBJECT', 'User') }, - ], + { name: 'currentUser', type: createTypeRef('OBJECT', 'User') } + ] } as ResolvedType); registry.set('Mutation', { @@ -205,8 +205,8 @@ function createTypeRegistry(): TypeRegistry { fields: [ { name: 'login', type: createTypeRef('OBJECT', 'LoginPayload') }, { name: 'logout', type: createTypeRef('OBJECT', 'LogoutPayload') }, - { name: 'register', type: createTypeRef('OBJECT', 'RegisterPayload') }, - ], + { name: 'register', type: createTypeRef('OBJECT', 'RegisterPayload') } + ] } as ResolvedType); return registry; @@ -217,7 +217,7 @@ describe('Query Hook Generators', () => { it('generates list query hook for simple table', () => { const result = generateListQueryHook(simpleUserTable, { reactQueryEnabled: true, - useCentralizedKeys: true, + useCentralizedKeys: true }); expect(result).not.toBeNull(); expect(result.fileName).toBe('useUsersQuery.ts'); @@ -227,7 +227,7 @@ describe('Query Hook Generators', () => { it('generates list query hook without centralized keys', () => { const result = generateListQueryHook(simpleUserTable, { reactQueryEnabled: true, - useCentralizedKeys: false, + useCentralizedKeys: false }); expect(result).not.toBeNull(); expect(result.content).toMatchSnapshot(); @@ -237,7 +237,7 @@ describe('Query Hook Generators', () => { const result = generateListQueryHook(postTable, { reactQueryEnabled: true, useCentralizedKeys: true, - hasRelationships: true, + hasRelationships: true }); expect(result).not.toBeNull(); expect(result.content).toMatchSnapshot(); @@ -248,7 +248,7 @@ describe('Query Hook Generators', () => { it('generates single query hook for simple table', () => { const result = generateSingleQueryHook(simpleUserTable, { reactQueryEnabled: true, - useCentralizedKeys: true, + useCentralizedKeys: true }); expect(result).not.toBeNull(); expect(result.fileName).toBe('useUserQuery.ts'); @@ -258,7 +258,7 @@ describe('Query Hook Generators', () => { it('generates single query hook without centralized keys', () => { const result = generateSingleQueryHook(simpleUserTable, { reactQueryEnabled: true, - useCentralizedKeys: false, + useCentralizedKeys: false }); expect(result).not.toBeNull(); expect(result.content).toMatchSnapshot(); @@ -268,7 +268,7 @@ describe('Query Hook Generators', () => { const result = generateSingleQueryHook(postTable, { reactQueryEnabled: true, useCentralizedKeys: true, - hasRelationships: true, + hasRelationships: true }); expect(result).not.toBeNull(); expect(result.content).toMatchSnapshot(); @@ -281,7 +281,7 @@ describe('Mutation Hook Generators', () => { it('generates create mutation hook for simple table', () => { const result = generateCreateMutationHook(simpleUserTable, { reactQueryEnabled: true, - useCentralizedKeys: true, + useCentralizedKeys: true }); expect(result).not.toBeNull(); expect(result!.fileName).toBe('useCreateUserMutation.ts'); @@ -291,7 +291,7 @@ describe('Mutation Hook Generators', () => { it('generates create mutation hook without centralized keys', () => { const result = generateCreateMutationHook(simpleUserTable, { reactQueryEnabled: true, - useCentralizedKeys: false, + useCentralizedKeys: false }); expect(result).not.toBeNull(); expect(result!.content).toMatchSnapshot(); @@ -300,8 +300,7 @@ describe('Mutation Hook Generators', () => { it('generates create mutation hook for table with relationships', () => { const result = generateCreateMutationHook(postTable, { reactQueryEnabled: true, - useCentralizedKeys: true, - hasRelationships: true, + useCentralizedKeys: true }); expect(result).not.toBeNull(); expect(result!.content).toMatchSnapshot(); @@ -312,7 +311,7 @@ describe('Mutation Hook Generators', () => { it('generates update mutation hook for simple table', () => { const result = generateUpdateMutationHook(simpleUserTable, { reactQueryEnabled: true, - useCentralizedKeys: true, + useCentralizedKeys: true }); expect(result).not.toBeNull(); expect(result!.fileName).toBe('useUpdateUserMutation.ts'); @@ -322,7 +321,7 @@ describe('Mutation Hook Generators', () => { it('generates update mutation hook without centralized keys', () => { const result = generateUpdateMutationHook(simpleUserTable, { reactQueryEnabled: true, - useCentralizedKeys: false, + useCentralizedKeys: false }); expect(result).not.toBeNull(); expect(result!.content).toMatchSnapshot(); @@ -331,8 +330,7 @@ describe('Mutation Hook Generators', () => { it('generates update mutation hook for table with relationships', () => { const result = generateUpdateMutationHook(postTable, { reactQueryEnabled: true, - useCentralizedKeys: true, - hasRelationships: true, + useCentralizedKeys: true }); expect(result).not.toBeNull(); expect(result!.content).toMatchSnapshot(); @@ -343,7 +341,7 @@ describe('Mutation Hook Generators', () => { it('generates delete mutation hook for simple table', () => { const result = generateDeleteMutationHook(simpleUserTable, { reactQueryEnabled: true, - useCentralizedKeys: true, + useCentralizedKeys: true }); expect(result).not.toBeNull(); expect(result!.fileName).toBe('useDeleteUserMutation.ts'); @@ -353,7 +351,7 @@ describe('Mutation Hook Generators', () => { it('generates delete mutation hook without centralized keys', () => { const result = generateDeleteMutationHook(simpleUserTable, { reactQueryEnabled: true, - useCentralizedKeys: false, + useCentralizedKeys: false }); expect(result).not.toBeNull(); expect(result!.content).toMatchSnapshot(); @@ -362,8 +360,7 @@ describe('Mutation Hook Generators', () => { it('generates delete mutation hook for table with relationships', () => { const result = generateDeleteMutationHook(postTable, { reactQueryEnabled: true, - useCentralizedKeys: true, - hasRelationships: true, + useCentralizedKeys: true }); expect(result).not.toBeNull(); expect(result!.content).toMatchSnapshot(); @@ -377,7 +374,7 @@ describe('Custom Query Hook Generators', () => { const result = generateCustomQueryHook({ operation: simpleCustomQueries[0], typeRegistry: createTypeRegistry(), - useCentralizedKeys: true, + useCentralizedKeys: true }); expect(result).not.toBeNull(); expect(result!.fileName).toBe('useCurrentUserQuery.ts'); @@ -388,7 +385,7 @@ describe('Custom Query Hook Generators', () => { const result = generateCustomQueryHook({ operation: simpleCustomQueries[1], typeRegistry: createTypeRegistry(), - useCentralizedKeys: true, + useCentralizedKeys: true }); expect(result).not.toBeNull(); expect(result!.fileName).toBe('useSearchUsersQuery.ts'); @@ -399,7 +396,7 @@ describe('Custom Query Hook Generators', () => { const result = generateCustomQueryHook({ operation: simpleCustomQueries[0], typeRegistry: createTypeRegistry(), - useCentralizedKeys: false, + useCentralizedKeys: false }); expect(result).not.toBeNull(); expect(result!.content).toMatchSnapshot(); @@ -413,7 +410,7 @@ describe('Custom Mutation Hook Generators', () => { const result = generateCustomMutationHook({ operation: simpleCustomMutations[0], typeRegistry: createTypeRegistry(), - useCentralizedKeys: true, + useCentralizedKeys: true }); expect(result).not.toBeNull(); expect(result!.fileName).toBe('useLoginMutation.ts'); @@ -424,7 +421,7 @@ describe('Custom Mutation Hook Generators', () => { const result = generateCustomMutationHook({ operation: simpleCustomMutations[1], typeRegistry: createTypeRegistry(), - useCentralizedKeys: true, + useCentralizedKeys: true }); expect(result).not.toBeNull(); expect(result!.fileName).toBe('useLogoutMutation.ts'); @@ -435,7 +432,7 @@ describe('Custom Mutation Hook Generators', () => { const result = generateCustomMutationHook({ operation: simpleCustomMutations[2], typeRegistry: createTypeRegistry(), - useCentralizedKeys: true, + useCentralizedKeys: true }); expect(result).not.toBeNull(); expect(result!.fileName).toBe('useRegisterMutation.ts'); @@ -446,7 +443,7 @@ describe('Custom Mutation Hook Generators', () => { const result = generateCustomMutationHook({ operation: simpleCustomMutations[0], typeRegistry: createTypeRegistry(), - useCentralizedKeys: false, + useCentralizedKeys: false }); expect(result).not.toBeNull(); expect(result!.content).toMatchSnapshot(); @@ -459,7 +456,7 @@ describe('Schema Types Generator', () => { it('generates schema types file with enums and input objects', () => { const result = generateSchemaTypesFile({ typeRegistry: createTypeRegistry(), - tableTypeNames: new Set(['User', 'Post']), + tableTypeNames: new Set(['User', 'Post']) }); expect(result.fileName).toBe('schema-types.ts'); expect(result.content).toMatchSnapshot(); @@ -468,7 +465,7 @@ describe('Schema Types Generator', () => { it('generates schema types file with empty table types', () => { const result = generateSchemaTypesFile({ typeRegistry: createTypeRegistry(), - tableTypeNames: new Set(), + tableTypeNames: new Set() }); expect(result.content).toMatchSnapshot(); }); @@ -503,27 +500,24 @@ 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, - hasInvalidation: true, + hasInvalidation: true }); expect(result).toMatchSnapshot(); }); it('generates main barrel without custom operations', () => { const result = generateMainBarrel([simpleUserTable], { - hasSchemaTypes: false, - hasMutations: true, + hasMutations: true }); expect(result).toMatchSnapshot(); }); it('generates main barrel without mutations', () => { const result = generateMainBarrel([simpleUserTable, postTable], { - hasSchemaTypes: true, - hasMutations: false, + hasMutations: false }); 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..93143400f 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,11 @@ * - 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 @@ -20,14 +20,14 @@ const fieldTypes = { uuid: { gqlType: 'UUID', isArray: false } as CleanFieldType, string: { gqlType: 'String', isArray: false } as CleanFieldType, int: { gqlType: 'Int', isArray: false } as CleanFieldType, - datetime: { gqlType: 'Datetime', isArray: false } as CleanFieldType, + datetime: { gqlType: 'Datetime', isArray: false } as CleanFieldType }; const emptyRelations: CleanRelations = { belongsTo: [], hasOne: [], hasMany: [], - manyToMany: [], + manyToMany: [] }; function createTable(partial: Partial & { name: string }): CleanTable { @@ -37,7 +37,7 @@ function createTable(partial: Partial & { name: string }): CleanTabl relations: partial.relations ?? emptyRelations, query: partial.query, inflection: partial.inflection, - constraints: partial.constraints, + constraints: partial.constraints }; } @@ -47,15 +47,15 @@ const userTable = createTable({ { name: 'id', type: fieldTypes.uuid }, { name: 'email', type: fieldTypes.string }, { name: 'name', type: fieldTypes.string }, - { name: 'createdAt', type: fieldTypes.datetime }, + { name: 'createdAt', type: fieldTypes.datetime } ], query: { all: 'users', one: 'user', create: 'createUser', update: 'updateUser', - delete: 'deleteUser', - }, + delete: 'deleteUser' + } }); function createTypeRef(kind: CleanTypeRef['kind'], name: string | null, ofType?: CleanTypeRef): CleanTypeRef { @@ -67,7 +67,7 @@ const sampleQueryOperation: CleanOperation = { kind: 'query', args: [], returnType: createTypeRef('OBJECT', 'User'), - description: 'Get the current authenticated user', + description: 'Get the current authenticated user' }; const sampleMutationOperation: CleanOperation = { @@ -75,10 +75,10 @@ const sampleMutationOperation: CleanOperation = { kind: 'mutation', args: [ { name: 'email', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) }, - { name: 'password', 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', + description: 'Authenticate user' }; const emptyTypeRegistry: TypeRegistry = new Map(); @@ -111,9 +111,9 @@ describe('Query generators with reactQueryEnabled: false', () => { expect(result.content).toContain('export async function fetchUsersQuery'); }); - it('should still include GraphQL document when disabled', () => { + it('should still include ORM client imports when disabled', () => { const result = generateListQueryHook(userTable, { reactQueryEnabled: false }); - expect(result.content).toContain('usersQueryDocument'); + expect(result.content).toContain('getClient'); }); it('should still include query key factory when disabled', () => { @@ -251,7 +251,7 @@ describe('Custom query generators with reactQueryEnabled: false', () => { const result = generateCustomQueryHook({ operation: sampleQueryOperation, typeRegistry: emptyTypeRegistry, - reactQueryEnabled: false, + reactQueryEnabled: false }); expect(result.content).not.toContain('@tanstack/react-query'); expect(result.content).not.toContain('useQuery'); @@ -261,7 +261,7 @@ describe('Custom query generators with reactQueryEnabled: false', () => { const result = generateCustomQueryHook({ operation: sampleQueryOperation, typeRegistry: emptyTypeRegistry, - reactQueryEnabled: false, + reactQueryEnabled: false }); expect(result.content).not.toContain('export function useCurrentUserQuery'); }); @@ -270,7 +270,7 @@ describe('Custom query generators with reactQueryEnabled: false', () => { const result = generateCustomQueryHook({ operation: sampleQueryOperation, typeRegistry: emptyTypeRegistry, - reactQueryEnabled: false, + reactQueryEnabled: false }); expect(result.content).toContain('export async function fetchCurrentUserQuery'); }); @@ -281,7 +281,7 @@ describe('Custom query generators with reactQueryEnabled: false', () => { const results = generateAllCustomQueryHooks({ operations: [sampleQueryOperation], typeRegistry: emptyTypeRegistry, - reactQueryEnabled: false, + reactQueryEnabled: false }); expect(results.length).toBe(1); expect(results[0].content).not.toContain('@tanstack/react-query'); @@ -299,7 +299,7 @@ describe('Custom mutation generators with reactQueryEnabled: false', () => { const result = generateCustomMutationHook({ operation: sampleMutationOperation, typeRegistry: emptyTypeRegistry, - reactQueryEnabled: false, + reactQueryEnabled: false }); expect(result).toBeNull(); }); @@ -310,7 +310,7 @@ describe('Custom mutation generators with reactQueryEnabled: false', () => { const results = generateAllCustomMutationHooks({ operations: [sampleMutationOperation], typeRegistry: emptyTypeRegistry, - reactQueryEnabled: false, + reactQueryEnabled: false }); expect(results).toEqual([]); }); @@ -326,7 +326,7 @@ describe('Custom mutation generators with reactQueryEnabled: true (default)', () it('should return mutation file by default', () => { const result = generateCustomMutationHook({ operation: sampleMutationOperation, - typeRegistry: emptyTypeRegistry, + typeRegistry: emptyTypeRegistry }); expect(result).not.toBeNull(); expect(result!.content).toContain('useMutation'); diff --git a/graphql/codegen/src/__tests__/codegen/scalars.test.ts b/graphql/codegen/src/__tests__/codegen/scalars.test.ts index 27539d3f4..7c81ae5c9 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', () => { 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..526013226 100644 --- a/graphql/codegen/src/__tests__/codegen/schema-types-generator.test.ts +++ b/graphql/codegen/src/__tests__/codegen/schema-types-generator.test.ts @@ -2,7 +2,7 @@ * 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 { return new Map(types); @@ -12,12 +12,12 @@ 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'] }], + ['Priority', { kind: 'ENUM', name: 'Priority', enumValues: ['LOW', 'MEDIUM', 'HIGH'] }] ]); const result = generateSchemaTypesFile({ typeRegistry: registry, - tableTypeNames: new Set(), + tableTypeNames: new Set() }); expect(result.content).toMatchSnapshot(); @@ -34,9 +34,9 @@ describe('schema-types-generator', () => { inputFields: [ { 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' } }, - ], - }, + { name: 'age', type: { kind: 'SCALAR', name: 'Int' } } + ] + } ], [ 'UpdateUserInput', @@ -45,15 +45,15 @@ describe('schema-types-generator', () => { name: 'UpdateUserInput', inputFields: [ { name: 'id', type: { kind: 'NON_NULL', name: null, ofType: { kind: 'SCALAR', name: 'UUID' } } }, - { name: 'name', type: { kind: 'SCALAR', name: 'String' } }, - ], - }, - ], + { name: 'name', type: { kind: 'SCALAR', name: 'String' } } + ] + } + ] ]); const result = generateSchemaTypesFile({ typeRegistry: registry, - tableTypeNames: new Set(), + tableTypeNames: new Set() }); expect(result.content).toMatchSnapshot(); @@ -61,12 +61,12 @@ 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({ typeRegistry: registry, - tableTypeNames: new Set(), + tableTypeNames: new Set() }); expect(result.content).toMatchSnapshot(); @@ -80,9 +80,9 @@ describe('schema-types-generator', () => { kind: 'OBJECT', name: 'Mutation', fields: [ - { name: 'login', type: { kind: 'OBJECT', name: 'LoginPayload' } }, - ], - }, + { name: 'login', type: { kind: 'OBJECT', name: 'LoginPayload' } } + ] + } ], [ 'LoginPayload', @@ -92,15 +92,15 @@ describe('schema-types-generator', () => { fields: [ { 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' } }, - ], - }, - ], + { name: 'user', type: { kind: 'OBJECT', name: 'User' } } + ] + } + ] ]); const result = generateSchemaTypesFile({ typeRegistry: registry, - tableTypeNames: new Set(['User']), + tableTypeNames: new Set(['User']) }); expect(result.content).toMatchSnapshot(); @@ -111,12 +111,12 @@ 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({ typeRegistry: registry, - tableTypeNames: new Set(['User']), + tableTypeNames: new Set(['User']) }); expect(result.content).toMatchSnapshot(); diff --git a/graphql/codegen/src/__tests__/codegen/utils.test.ts b/graphql/codegen/src/__tests__/codegen/utils.test.ts index 62dbf33a0..38f9f066d 100644 --- a/graphql/codegen/src/__tests__/codegen/utils.test.ts +++ b/graphql/codegen/src/__tests__/codegen/utils.test.ts @@ -2,25 +2,25 @@ * 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: [], hasOne: [], hasMany: [], - manyToMany: [], + manyToMany: [] }; // Use any for test fixture overrides to avoid strict type requirements @@ -29,7 +29,7 @@ function createTable(name: string, overrides: Record = {}): Cle name, fields: [], relations: emptyRelations, - ...overrides, + ...overrides } as CleanTable; } @@ -78,7 +78,7 @@ describe('utils', () => { it('uses inflection overrides when provided', () => { const result = getTableNames( createTable('Person', { - inflection: { tableFieldName: 'individual', allRows: 'people' }, + inflection: { tableFieldName: 'individual', allRows: 'people' } }) ); expect(result.singularName).toBe('individual'); @@ -88,7 +88,7 @@ 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'); @@ -138,8 +138,8 @@ 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' }]); @@ -147,7 +147,7 @@ describe('utils', () => { it('falls back to id field', () => { const table = createTable('User', { - fields: [{ name: 'id', type: { gqlType: 'UUID', isArray: false } }], + fields: [{ name: 'id', type: { gqlType: 'UUID', isArray: false } }] }); const result = getPrimaryKeyInfo(table); expect(result).toEqual([{ name: 'id', gqlType: 'UUID', tsType: 'string' }]); @@ -161,11 +161,11 @@ describe('utils', () => { name: 'user_roles_pkey', fields: [ { name: 'userId', type: { gqlType: 'UUID', isArray: false } }, - { name: 'roleId', type: { gqlType: 'UUID', isArray: false } }, - ], - }, - ], - }, + { name: 'roleId', type: { gqlType: 'UUID', isArray: false } } + ] + } + ] + } }); const result = getPrimaryKeyInfo(table); expect(result).toHaveLength(2); diff --git a/graphql/codegen/src/__tests__/config/resolve-config.test.ts b/graphql/codegen/src/__tests__/config/resolve-config.test.ts index e7e879345..c3d5cd162 100644 --- a/graphql/codegen/src/__tests__/config/resolve-config.test.ts +++ b/graphql/codegen/src/__tests__/config/resolve-config.test.ts @@ -1,16 +1,16 @@ import type { - GraphQLSDKConfigTarget, + GraphQLSDKConfigTarget } from '../../types/config'; import { - mergeConfig, - getConfigOptions, DEFAULT_CONFIG, + getConfigOptions, + mergeConfig } from '../../types/config'; describe('config resolution', () => { it('resolves config with defaults', () => { const config: GraphQLSDKConfigTarget = { - endpoint: 'https://api.example.com/graphql', + endpoint: 'https://api.example.com/graphql' }; const resolved = getConfigOptions(config); @@ -29,9 +29,9 @@ describe('config resolution', () => { tables: { include: ['User'] }, queryKeys: { relationships: { - database: { parent: 'organization', foreignKey: 'organizationId' }, - }, - }, + database: { parent: 'organization', foreignKey: 'organizationId' } + } + } }; const overrides: GraphQLSDKConfigTarget = { @@ -40,9 +40,9 @@ describe('config resolution', () => { tables: { exclude: ['_internal'] }, queryKeys: { relationships: { - table: { parent: 'database', foreignKey: 'databaseId' }, - }, - }, + table: { parent: 'database', foreignKey: 'databaseId' } + } + } }; const merged = mergeConfig(base, overrides); @@ -50,15 +50,15 @@ describe('config resolution', () => { expect(merged.output).toBe('./generated/custom'); expect(merged.headers).toEqual({ Authorization: 'Bearer base', - 'X-Custom': '1', + 'X-Custom': '1' }); expect(merged.tables).toEqual({ include: ['User'], - exclude: ['_internal'], + exclude: ['_internal'] }); expect(merged.queryKeys?.relationships).toEqual({ database: { parent: 'organization', foreignKey: 'organizationId' }, - table: { parent: 'database', foreignKey: 'databaseId' }, + table: { parent: 'database', foreignKey: 'databaseId' } }); }); }); diff --git a/graphql/codegen/src/__tests__/introspect/infer-tables.test.ts b/graphql/codegen/src/__tests__/introspect/infer-tables.test.ts index af8828802..80091abed 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 { - IntrospectionQueryResponse, - IntrospectionType, - IntrospectionTypeRef, + IntrospectionEnumValue, IntrospectionField, IntrospectionInputValue, - IntrospectionEnumValue, + IntrospectionQueryResponse, + IntrospectionType, + IntrospectionTypeRef } from '../../types/introspection'; // ============================================================================ @@ -99,19 +99,19 @@ function createIntrospection( name: a.name, type: a.type, description: null, - defaultValue: null, + defaultValue: null }) ), deprecationReason: null, description: null, - isDeprecated: false, + isDeprecated: false }); const makeInputField = (f: InputFieldDef): IntrospectionInputValue => ({ name: f.name, type: f.type, description: null, - defaultValue: null, + defaultValue: null }); // Add Query and Mutation types @@ -124,21 +124,21 @@ function createIntrospection( enumValues: null, interfaces: [], possibleTypes: null, - description: null, + description: null }, ...(mutationFields.length > 0 ? [ - { - name: 'Mutation', - kind: 'OBJECT' as const, - fields: mutationFields.map(makeField), - inputFields: null, - enumValues: null, - interfaces: [], - possibleTypes: null, - description: null, - }, - ] + { + name: 'Mutation', + kind: 'OBJECT' as const, + fields: mutationFields.map(makeField), + inputFields: null, + enumValues: null, + interfaces: [], + possibleTypes: null, + description: null + } + ] : []), ...types.map( (t): IntrospectionType => ({ @@ -152,19 +152,19 @@ function createIntrospection( enumValues: t.kind === 'ENUM' ? (t.enumValues ?? []).map( - (v): IntrospectionEnumValue => ({ - name: v, - deprecationReason: null, - description: null, - isDeprecated: false, - }) - ) + (v): IntrospectionEnumValue => ({ + name: v, + deprecationReason: null, + description: null, + isDeprecated: false + }) + ) : null, interfaces: [], possibleTypes: null, - description: null, + description: null }) - ), + ) ]; return { @@ -173,8 +173,8 @@ function createIntrospection( mutationType: mutationFields.length > 0 ? { name: 'Mutation' } : null, subscriptionType: null, types: allTypes, - directives: [], - }, + directives: [] + } }; } @@ -192,8 +192,8 @@ describe('Entity Detection', () => { kind: 'OBJECT', fields: [ { name: 'id', type: nonNull(scalar('UUID')) }, - { name: 'email', type: scalar('String') }, - ], + { name: 'email', type: scalar('String') } + ] }, // UsersConnection type (indicates User is an entity) { @@ -201,15 +201,15 @@ describe('Entity Detection', () => { kind: 'OBJECT', fields: [ { name: 'nodes', type: list(object('User')) }, - { name: 'pageInfo', type: nonNull(object('PageInfo')) }, - ], + { name: 'pageInfo', type: nonNull(object('PageInfo')) } + ] }, // PageInfo (builtin, should be ignored) - { name: 'PageInfo', kind: 'OBJECT', fields: [] }, + { name: 'PageInfo', kind: 'OBJECT', fields: [] } ], [ // Query for users - { name: 'users', type: object('UsersConnection') }, + { name: 'users', type: object('UsersConnection') } ] ); @@ -225,26 +225,26 @@ describe('Entity Detection', () => { { name: 'User', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, { name: 'Post', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, { name: 'PostsConnection', kind: 'OBJECT', fields: [] }, { name: 'Comment', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, - { name: 'CommentsConnection', kind: 'OBJECT', fields: [] }, + { name: 'CommentsConnection', kind: 'OBJECT', fields: [] } ], [ { name: 'users', type: object('UsersConnection') }, { name: 'posts', type: object('PostsConnection') }, - { name: 'comments', type: object('CommentsConnection') }, + { name: 'comments', type: object('CommentsConnection') } ] ); @@ -261,15 +261,15 @@ describe('Entity Detection', () => { { name: 'User', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, // Does not have Connection (should be ignored) { name: 'AuditLog', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], - }, + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] + } ], [{ name: 'users', type: object('UsersConnection') }] ); @@ -297,10 +297,10 @@ describe('Field Extraction', () => { { name: 'email', type: scalar('String') }, { name: 'age', type: scalar('Int') }, { name: 'isActive', type: scalar('Boolean') }, - { name: 'metadata', type: scalar('JSON') }, - ], + { name: 'metadata', type: scalar('JSON') } + ] }, - { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, + { name: 'UsersConnection', kind: 'OBJECT', fields: [] } ], [{ name: 'users', type: object('UsersConnection') }] ); @@ -314,7 +314,7 @@ describe('Field Extraction', () => { 'email', 'age', 'isActive', - 'metadata', + 'metadata' ]); expect(fields.find((f) => f.name === 'id')?.type.gqlType).toBe('UUID'); expect(fields.find((f) => f.name === 'email')?.type.gqlType).toBe('String'); @@ -328,10 +328,10 @@ describe('Field Extraction', () => { kind: 'OBJECT', fields: [ { name: 'id', type: nonNull(scalar('UUID')) }, - { name: 'tags', type: list(scalar('String')) }, - ], + { name: 'tags', type: list(scalar('String')) } + ] }, - { name: 'PostsConnection', kind: 'OBJECT', fields: [] }, + { name: 'PostsConnection', kind: 'OBJECT', fields: [] } ], [{ name: 'posts', type: object('PostsConnection') }] ); @@ -354,27 +354,27 @@ describe('Field Extraction', () => { { name: 'id', type: nonNull(scalar('UUID')) }, { name: 'title', type: scalar('String') }, { name: 'author', type: object('User') }, // belongsTo relation - { name: 'comments', type: object('CommentsConnection') }, // hasMany relation - ], + { name: 'comments', type: object('CommentsConnection') } // hasMany relation + ] }, { name: 'PostsConnection', kind: 'OBJECT', fields: [] }, { name: 'User', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, { name: 'Comment', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, - { name: 'CommentsConnection', kind: 'OBJECT', fields: [] }, + { name: 'CommentsConnection', kind: 'OBJECT', fields: [] } ], [ { name: 'posts', type: object('PostsConnection') }, { name: 'users', type: object('UsersConnection') }, - { name: 'comments', type: object('CommentsConnection') }, + { name: 'comments', type: object('CommentsConnection') } ] ); @@ -402,20 +402,20 @@ describe('Relation Inference', () => { kind: 'OBJECT', fields: [ { name: 'id', type: nonNull(scalar('UUID')) }, - { name: 'author', type: object('User') }, - ], + { name: 'author', type: object('User') } + ] }, { name: 'PostsConnection', kind: 'OBJECT', fields: [] }, { name: 'User', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, - { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, + { name: 'UsersConnection', kind: 'OBJECT', fields: [] } ], [ { name: 'posts', type: object('PostsConnection') }, - { name: 'users', type: object('UsersConnection') }, + { name: 'users', type: object('UsersConnection') } ] ); @@ -435,20 +435,20 @@ describe('Relation Inference', () => { kind: 'OBJECT', fields: [ { name: 'id', type: nonNull(scalar('UUID')) }, - { name: 'posts', type: object('PostsConnection') }, - ], + { name: 'posts', type: object('PostsConnection') } + ] }, { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, { name: 'Post', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, - { name: 'PostsConnection', kind: 'OBJECT', fields: [] }, + { name: 'PostsConnection', kind: 'OBJECT', fields: [] } ], [ { name: 'users', type: object('UsersConnection') }, - { name: 'posts', type: object('PostsConnection') }, + { name: 'posts', type: object('PostsConnection') } ] ); @@ -471,21 +471,21 @@ describe('Relation Inference', () => { // ManyToMany pattern: {entities}By{JunctionTable}{Keys} { name: 'productsByProductCategoryProductIdAndCategoryId', - type: object('ProductsConnection'), - }, - ], + type: object('ProductsConnection') + } + ] }, { name: 'CategoriesConnection', kind: 'OBJECT', fields: [] }, { name: 'Product', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, - { name: 'ProductsConnection', kind: 'OBJECT', fields: [] }, + { name: 'ProductsConnection', kind: 'OBJECT', fields: [] } ], [ { name: 'categories', type: object('CategoriesConnection') }, - { name: 'products', type: object('ProductsConnection') }, + { name: 'products', type: object('ProductsConnection') } ] ); @@ -511,9 +511,9 @@ describe('Query Operation Matching', () => { { name: 'User', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, - { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, + { name: 'UsersConnection', kind: 'OBJECT', fields: [] } ], [{ name: 'allUsers', type: object('UsersConnection') }] ); @@ -529,17 +529,17 @@ describe('Query Operation Matching', () => { { name: 'User', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, - { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, + { name: 'UsersConnection', kind: 'OBJECT', fields: [] } ], [ { name: 'users', type: object('UsersConnection') }, { name: 'user', type: object('User'), - args: [{ name: 'id', type: nonNull(scalar('UUID')) }], - }, + args: [{ name: 'id', type: nonNull(scalar('UUID')) }] + } ] ); @@ -554,12 +554,12 @@ describe('Query Operation Matching', () => { { name: 'User', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, - { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, + { name: 'UsersConnection', kind: 'OBJECT', fields: [] } ], [ - { name: 'users', type: object('UsersConnection') }, + { name: 'users', type: object('UsersConnection') } // No single user query ] ); @@ -579,10 +579,10 @@ describe('Mutation Operation Matching', () => { { name: 'User', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, - { name: 'CreateUserPayload', kind: 'OBJECT', fields: [] }, + { name: 'CreateUserPayload', kind: 'OBJECT', fields: [] } ], [{ name: 'users', type: object('UsersConnection') }], [ @@ -590,9 +590,9 @@ describe('Mutation Operation Matching', () => { name: 'createUser', type: object('CreateUserPayload'), args: [ - { name: 'input', type: nonNull(inputObject('CreateUserInput')) }, - ], - }, + { name: 'input', type: nonNull(inputObject('CreateUserInput')) } + ] + } ] ); @@ -607,11 +607,11 @@ describe('Mutation Operation Matching', () => { { name: 'User', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, { name: 'UpdateUserPayload', kind: 'OBJECT', fields: [] }, - { name: 'DeleteUserPayload', kind: 'OBJECT', fields: [] }, + { name: 'DeleteUserPayload', kind: 'OBJECT', fields: [] } ], [{ name: 'users', type: object('UsersConnection') }], [ @@ -619,16 +619,16 @@ describe('Mutation Operation Matching', () => { name: 'updateUser', type: object('UpdateUserPayload'), args: [ - { name: 'input', type: nonNull(inputObject('UpdateUserInput')) }, - ], + { name: 'input', type: nonNull(inputObject('UpdateUserInput')) } + ] }, { name: 'deleteUser', type: object('DeleteUserPayload'), args: [ - { name: 'input', type: nonNull(inputObject('DeleteUserInput')) }, - ], - }, + { name: 'input', type: nonNull(inputObject('DeleteUserInput')) } + ] + } ] ); @@ -644,15 +644,15 @@ describe('Mutation Operation Matching', () => { { name: 'User', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, - { name: 'UpdateUserPayload', kind: 'OBJECT', fields: [] }, + { name: 'UpdateUserPayload', kind: 'OBJECT', fields: [] } ], [{ name: 'users', type: object('UsersConnection') }], [ { name: 'updateUserById', type: object('UpdateUserPayload') }, - { name: 'updateUser', type: object('UpdateUserPayload') }, + { name: 'updateUser', type: object('UpdateUserPayload') } ] ); @@ -673,9 +673,9 @@ describe('Constraint Inference', () => { { name: 'User', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, - { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, + { name: 'UsersConnection', kind: 'OBJECT', fields: [] } ], [{ name: 'users', type: object('UsersConnection') }] ); @@ -692,14 +692,14 @@ describe('Constraint Inference', () => { { name: 'User', kind: 'OBJECT', - fields: [{ name: 'userId', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'userId', type: nonNull(scalar('UUID')) }] }, { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, { name: 'UpdateUserInput', kind: 'INPUT_OBJECT', - inputFields: [{ name: 'id', type: nonNull(scalar('UUID')) }], - }, + inputFields: [{ name: 'id', type: nonNull(scalar('UUID')) }] + } ], [{ name: 'users', type: object('UsersConnection') }], [{ name: 'updateUser', type: object('UpdateUserPayload') }] @@ -723,12 +723,12 @@ describe('Inflection Building', () => { { name: 'User', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, { name: 'UserFilter', kind: 'INPUT_OBJECT', inputFields: [] }, { name: 'UserPatch', kind: 'INPUT_OBJECT', inputFields: [] }, - { name: 'UpdateUserPayload', kind: 'OBJECT', fields: [] }, + { name: 'UpdateUserPayload', kind: 'OBJECT', fields: [] } ], [{ name: 'users', type: object('UsersConnection') }] ); @@ -750,9 +750,9 @@ describe('Inflection Building', () => { { name: 'User', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, - { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, + { name: 'UsersConnection', kind: 'OBJECT', fields: [] } // No UserFilter, UserPatch, or UpdateUserPayload ], [{ name: 'users', type: object('UsersConnection') }] @@ -776,7 +776,7 @@ describe('Edge Cases', () => { const introspection = createIntrospection( [ // Only built-in types, no entities - { name: 'PageInfo', kind: 'OBJECT', fields: [] }, + { name: 'PageInfo', kind: 'OBJECT', fields: [] } ], [] ); @@ -793,9 +793,9 @@ describe('Edge Cases', () => { { name: 'Orphan', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, - { name: 'OrphansConnection', kind: 'OBJECT', fields: [] }, + { name: 'OrphansConnection', kind: 'OBJECT', fields: [] } ], [] // No query fields ); @@ -814,8 +814,8 @@ describe('Edge Cases', () => { kind: 'OBJECT', fields: [ { name: 'id', type: nonNull(scalar('UUID')) }, - { name: 'posts', type: object('PostsConnection') }, - ], + { name: 'posts', type: object('PostsConnection') } + ] }, { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, { @@ -823,14 +823,14 @@ describe('Edge Cases', () => { kind: 'OBJECT', fields: [ { name: 'id', type: nonNull(scalar('UUID')) }, - { name: 'author', type: object('User') }, - ], + { name: 'author', type: object('User') } + ] }, - { name: 'PostsConnection', kind: 'OBJECT', fields: [] }, + { name: 'PostsConnection', kind: 'OBJECT', fields: [] } ], [ { name: 'users', type: object('UsersConnection') }, - { name: 'posts', type: object('PostsConnection') }, + { name: 'posts', type: object('PostsConnection') } ] ); @@ -852,9 +852,9 @@ describe('Edge Cases', () => { { name: 'Person', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, - { name: 'PeopleConnection', kind: 'OBJECT', fields: [] }, + { name: 'PeopleConnection', kind: 'OBJECT', fields: [] } ], [{ name: 'people', type: object('PeopleConnection') }] ); @@ -875,15 +875,15 @@ describe('Edge Cases', () => { fields: [ { name: 'id', type: nonNull(scalar('UUID')) }, { name: 'street', type: scalar('String') }, - { name: 'city', type: scalar('String') }, - ], + { name: 'city', type: scalar('String') } + ] }, { name: 'AddressesConnection', kind: 'OBJECT', fields: [] }, { name: 'AddressesOrderBy', kind: 'ENUM', - enumValues: ['ID_ASC', 'ID_DESC'], - }, + enumValues: ['ID_ASC', 'ID_DESC'] + } ], [{ name: 'addresses', type: object('AddressesConnection') }] ); @@ -903,10 +903,10 @@ describe('Edge Cases', () => { { name: 'Category', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, { name: 'CategoriesConnection', kind: 'OBJECT', fields: [] }, - { name: 'CategoriesOrderBy', kind: 'ENUM', enumValues: ['ID_ASC'] }, + { name: 'CategoriesOrderBy', kind: 'ENUM', enumValues: ['ID_ASC'] } ], [{ name: 'categories', type: object('CategoriesConnection') }] ); @@ -923,11 +923,11 @@ describe('Edge Cases', () => { { name: 'Status', kind: 'OBJECT', - fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], + fields: [{ name: 'id', type: nonNull(scalar('UUID')) }] }, { name: 'StatusesConnection', kind: 'OBJECT', fields: [] }, // Schema has the actual OrderBy enum - { name: 'StatusesOrderBy', kind: 'ENUM', enumValues: ['ID_ASC'] }, + { name: 'StatusesOrderBy', kind: 'ENUM', enumValues: ['ID_ASC'] } ], [{ name: 'statuses', type: object('StatusesConnection') }] ); diff --git a/graphql/codegen/src/cli/index.ts b/graphql/codegen/src/cli/index.ts index 5ef53ee8c..6698e2a38 100644 --- a/graphql/codegen/src/cli/index.ts +++ b/graphql/codegen/src/cli/index.ts @@ -5,12 +5,12 @@ * 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 { camelizeArgv, type CodegenAnswers,codegenQuestions, printResult } from './shared'; const usage = ` graphql-codegen - GraphQL SDK generator for Constructive databases @@ -61,6 +61,15 @@ export const commands = async ( const configPath = (argv.config || argv.c || findConfigFile()) as string | undefined; const targetName = (argv.target || argv.t) as string | undefined; + // Collect CLI flags that should override config file settings + const cliOverrides: Partial = {}; + if (argv['react-query'] === true) cliOverrides.reactQuery = true; + if (argv.orm === true) cliOverrides.orm = true; + if (argv.verbose === true || argv.v === true) cliOverrides.verbose = true; + if (argv['dry-run'] === true) cliOverrides.dryRun = true; + if (argv.output || argv.o) cliOverrides.output = (argv.output || argv.o) as string; + if (argv.authorization || argv.a) cliOverrides.authorization = (argv.authorization || argv.a) as string; + // If config file exists, load and run if (configPath) { const loaded = await loadConfigFile(configPath); @@ -87,7 +96,7 @@ export const commands = async ( let hasError = false; for (const name of names) { console.log(`\n[${name}]`); - const result = await generate(targets[name]); + const result = await generate({ ...targets[name], ...cliOverrides }); printResult(result); if (!result.success) hasError = true; } @@ -97,8 +106,8 @@ export const commands = async ( return argv; } - // Single config - const result = await generate(config as GraphQLSDKConfigTarget); + // Single config — merge CLI overrides + const result = await generate({ ...(config as GraphQLSDKConfigTarget), ...cliOverrides }); printResult(result); if (!result.success) process.exit(1); prompter.close(); @@ -114,7 +123,7 @@ export const commands = async ( // Build db config if schemas or apiNames provided const db = (camelized.schemas || camelized.apiNames) ? { schemas: camelized.schemas, - apiNames: camelized.apiNames, + apiNames: camelized.apiNames } : undefined; const result = await generate({ @@ -127,7 +136,7 @@ export const commands = async ( orm: camelized.orm, browserCompatible: camelized.browserCompatible, dryRun: camelized.dryRun, - verbose: camelized.verbose, + verbose: camelized.verbose }); printResult(result); @@ -145,17 +154,17 @@ export const options: Partial = { o: 'output', t: 'target', a: 'authorization', - v: 'verbose', + v: 'verbose' }, boolean: [ - 'help', 'version', 'verbose', 'dry-run', 'react-query', 'orm', 'keep-db', 'browser-compatible', + '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', - ], - }, + 'schemas', 'api-names' + ] + } }; if (require.main === module) { diff --git a/graphql/codegen/src/cli/shared.ts b/graphql/codegen/src/cli/shared.ts index f147b9fa8..a1dee66a5 100644 --- a/graphql/codegen/src/cli/shared.ts +++ b/graphql/codegen/src/cli/shared.ts @@ -4,10 +4,11 @@ * These are exported so that packages/cli can use the same questions * and types, 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'; + +import type { GenerateResult } from '../core/generate'; /** * Sanitize function that splits comma-separated strings into arrays @@ -43,13 +44,13 @@ export const codegenQuestions: Question[] = [ name: 'endpoint', message: 'GraphQL endpoint URL', type: 'text', - required: false, + required: false }, { name: 'schema-file', message: 'Path to GraphQL schema file', type: 'text', - required: false, + required: false }, { name: 'output', @@ -57,21 +58,21 @@ export const codegenQuestions: Question[] = [ type: 'text', required: false, default: 'codegen', - useDefault: true, + useDefault: true }, { name: 'schemas', message: 'PostgreSQL schemas (comma-separated)', type: 'text', required: false, - sanitize: splitCommas, + sanitize: splitCommas }, { name: 'api-names', message: 'API names (comma-separated)', type: 'text', required: false, - sanitize: splitCommas, + sanitize: splitCommas }, { name: 'react-query', @@ -79,7 +80,7 @@ export const codegenQuestions: Question[] = [ type: 'confirm', required: false, default: false, - useDefault: true, + useDefault: true }, { name: 'orm', @@ -87,7 +88,7 @@ export const codegenQuestions: Question[] = [ type: 'confirm', required: false, default: false, - useDefault: true, + useDefault: true }, { name: 'browser-compatible', @@ -95,13 +96,13 @@ export const codegenQuestions: Question[] = [ type: 'confirm', required: false, default: true, - useDefault: true, + useDefault: true }, { name: 'authorization', message: 'Authorization header value', type: 'text', - required: false, + required: false }, { name: 'dry-run', @@ -109,7 +110,7 @@ export const codegenQuestions: Question[] = [ type: 'confirm', required: false, default: false, - useDefault: true, + useDefault: true }, { name: 'verbose', @@ -117,8 +118,8 @@ export const codegenQuestions: Question[] = [ type: 'confirm', required: false, default: false, - useDefault: true, - }, + useDefault: true + } ]; /** diff --git a/graphql/codegen/src/client/error.ts b/graphql/codegen/src/client/error.ts index d879712de..368094f84 100644 --- a/graphql/codegen/src/client/error.ts +++ b/graphql/codegen/src/client/error.ts @@ -43,7 +43,7 @@ export const DataErrorType = { EXCLUSION_VIOLATION: 'EXCLUSION_VIOLATION', // Generic errors - UNKNOWN_ERROR: 'UNKNOWN_ERROR', + UNKNOWN_ERROR: 'UNKNOWN_ERROR' } as const; export type DataErrorType = (typeof DataErrorType)[keyof typeof DataErrorType]; @@ -91,36 +91,36 @@ export class DataError extends Error { getUserMessage(): string { switch (this.type) { - case DataErrorType.NETWORK_ERROR: - return 'Network error. Please check your connection and try again.'; - case DataErrorType.TIMEOUT_ERROR: - return 'Request timed out. Please try again.'; - case DataErrorType.UNAUTHORIZED: - return 'You are not authorized. Please log in and try again.'; - case DataErrorType.FORBIDDEN: - return 'You do not have permission to access this resource.'; - case DataErrorType.VALIDATION_FAILED: - return 'Validation failed. Please check your input and try again.'; - case DataErrorType.REQUIRED_FIELD_MISSING: - return this.fieldName - ? `The field "${this.fieldName}" is required.` - : 'A required field is missing.'; - case DataErrorType.UNIQUE_VIOLATION: - return this.fieldName - ? `A record with this ${this.fieldName} already exists.` - : 'A record with this value already exists.'; - case DataErrorType.FOREIGN_KEY_VIOLATION: - return 'This record references a record that does not exist.'; - case DataErrorType.NOT_NULL_VIOLATION: - return this.fieldName - ? `The field "${this.fieldName}" cannot be empty.` - : 'A required field cannot be empty.'; - case DataErrorType.CHECK_VIOLATION: - return this.fieldName - ? `The value for "${this.fieldName}" is not valid.` - : 'The value does not meet the required constraints.'; - default: - return this.message || 'An unexpected error occurred.'; + case DataErrorType.NETWORK_ERROR: + return 'Network error. Please check your connection and try again.'; + case DataErrorType.TIMEOUT_ERROR: + return 'Request timed out. Please try again.'; + case DataErrorType.UNAUTHORIZED: + return 'You are not authorized. Please log in and try again.'; + case DataErrorType.FORBIDDEN: + return 'You do not have permission to access this resource.'; + case DataErrorType.VALIDATION_FAILED: + return 'Validation failed. Please check your input and try again.'; + case DataErrorType.REQUIRED_FIELD_MISSING: + return this.fieldName + ? `The field "${this.fieldName}" is required.` + : 'A required field is missing.'; + case DataErrorType.UNIQUE_VIOLATION: + return this.fieldName + ? `A record with this ${this.fieldName} already exists.` + : 'A record with this value already exists.'; + case DataErrorType.FOREIGN_KEY_VIOLATION: + return 'This record references a record that does not exist.'; + case DataErrorType.NOT_NULL_VIOLATION: + return this.fieldName + ? `The field "${this.fieldName}" cannot be empty.` + : 'A required field cannot be empty.'; + case DataErrorType.CHECK_VIOLATION: + return this.fieldName + ? `The value for "${this.fieldName}" is not valid.` + : 'The value does not meet the required constraints.'; + default: + return this.message || 'An unexpected error occurred.'; } } @@ -148,7 +148,7 @@ export const PG_ERROR_CODES = { DATETIME_FIELD_OVERFLOW: '22008', UNDEFINED_TABLE: '42P01', UNDEFINED_COLUMN: '42703', - INSUFFICIENT_PRIVILEGE: '42501', + INSUFFICIENT_PRIVILEGE: '42501' } as const; // ============================================================================ @@ -187,7 +187,7 @@ export const createError = { 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 }) }; // ============================================================================ @@ -293,7 +293,7 @@ export function parseGraphQLError(error: unknown): DataError { code: extCode, fieldName, constraint, - context: gqlError.extensions, + context: gqlError.extensions }); } @@ -303,7 +303,7 @@ export function parseGraphQLError(error: unknown): DataError { code: extCode, fieldName, constraint, - context: gqlError.extensions, + context: gqlError.extensions }); } diff --git a/graphql/codegen/src/client/execute.ts b/graphql/codegen/src/client/execute.ts index 6f59e7cec..1c4441acf 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 @@ -69,7 +69,7 @@ export async function execute( endpoint: string, document: TDocument, variables?: VariablesOf, - options: ExecuteOptions = {}, + options: ExecuteOptions = {} ): Promise> { const { headers = {}, timeout = 30000, signal } = options; @@ -88,13 +88,13 @@ export async function execute( headers: { 'Content-Type': 'application/json', Accept: 'application/graphql-response+json, application/json', - ...headers, + ...headers }, body: JSON.stringify({ query: documentToString(document), - ...(variables !== undefined && { variables }), + ...(variables !== undefined && { variables }) }), - signal: combinedSignal, + signal: combinedSignal }); clearTimeout(timeoutId); @@ -182,12 +182,12 @@ export function createGraphQLClient(options: GraphQLClientOptions) { async execute( document: TDocument, variables?: VariablesOf, - options: ExecuteOptions = {}, + options: ExecuteOptions = {} ): Promise> { return execute(endpoint, document, variables, { headers: { ...defaultHeaders, ...options.headers }, timeout: options.timeout ?? defaultTimeout, - signal: options.signal, + signal: options.signal }); }, @@ -196,7 +196,7 @@ export function createGraphQLClient(options: GraphQLClientOptions) { */ getEndpoint(): string { return endpoint; - }, + } }; } diff --git a/graphql/codegen/src/client/index.ts b/graphql/codegen/src/client/index.ts index 53b0bb352..2ec241259 100644 --- a/graphql/codegen/src/client/index.ts +++ b/graphql/codegen/src/client/index.ts @@ -2,24 +2,22 @@ * Client exports */ -export { TypedDocumentString, type DocumentTypeDecoration } from './typed-document'; - export { - DataError, - DataErrorType, createError, - parseGraphQLError, - isDataError, - PG_ERROR_CODES, + DataError, type DataErrorOptions, + DataErrorType, type GraphQLError, + isDataError, + parseGraphQLError, + PG_ERROR_CODES } from './error'; - export { - execute, createGraphQLClient, + execute, type ExecuteOptions, - type GraphQLClientOptions, type GraphQLClient, - type GraphQLResponse, + type GraphQLClientOptions, + type GraphQLResponse } from './execute'; +export { type DocumentTypeDecoration,TypedDocumentString } from './typed-document'; diff --git a/graphql/codegen/src/client/typed-document.ts b/graphql/codegen/src/client/typed-document.ts index ca3f895a4..95350ad96 100644 --- a/graphql/codegen/src/client/typed-document.ts +++ b/graphql/codegen/src/client/typed-document.ts @@ -33,7 +33,7 @@ export class TypedDocumentString this.value = value; this.__meta__ = { hash: this.generateHash(value), - ...meta, + ...meta }; } diff --git a/graphql/codegen/src/core/ast.ts b/graphql/codegen/src/core/ast.ts index d7903bd09..7c3b95db7 100644 --- a/graphql/codegen/src/core/ast.ts +++ b/graphql/codegen/src/core/ast.ts @@ -5,19 +5,18 @@ import type { FieldNode, TypeNode, ValueNode, - VariableDefinitionNode, + VariableDefinitionNode } from 'graphql'; import { camelize, singularize } from 'inflekt'; - import { getCustomAst } from './custom-ast'; import type { ASTFunctionParams, - QueryFieldSelection, MutationASTParams, NestedProperties, ObjectArrayItem, - QueryProperty, + QueryFieldSelection, + QueryProperty } from './types'; const NON_MUTABLE_PROPS = ['createdAt', 'createdBy', 'updatedAt', 'updatedBy']; @@ -32,7 +31,7 @@ const objectToArray = ( isNotNull: obj[k].isNotNull, isArray: obj[k].isArray, isArrayNotNull: obj[k].isArrayNotNull, - properties: obj[k].properties, + properties: obj[k].properties })); interface CreateGqlMutationParams { @@ -52,32 +51,32 @@ const createGqlMutation = ({ selections, variableDefinitions, modelName, - useModel = true, + useModel = true }: CreateGqlMutationParams): DocumentNode => { const opSel: FieldNode[] = !modelName ? [ - t.field({ - name: operationName, - args: selectArgs, - selectionSet: t.selectionSet({ selections }), - }), - ] + t.field({ + name: operationName, + args: selectArgs, + selectionSet: t.selectionSet({ selections }) + }) + ] : [ - t.field({ - name: operationName, - args: selectArgs, - selectionSet: t.selectionSet({ - selections: useModel - ? [ - t.field({ - name: modelName, - selectionSet: t.selectionSet({ selections }), - }), - ] - : selections, - }), - }), - ]; + t.field({ + name: operationName, + args: selectArgs, + selectionSet: t.selectionSet({ + selections: useModel + ? [ + t.field({ + name: modelName, + selectionSet: t.selectionSet({ selections }) + }) + ] + : selections + }) + }) + ]; return t.document({ definitions: [ @@ -85,16 +84,16 @@ const createGqlMutation = ({ operation: 'mutation', name: mutationName, variableDefinitions, - selectionSet: t.selectionSet({ selections: opSel }), - }), - ], + selectionSet: t.selectionSet({ selections: opSel }) + }) + ] }); }; export const getAll = ({ queryName, operationName, - selection, + selection }: ASTFunctionParams): DocumentNode => { const selections = getSelections(selection); @@ -104,15 +103,15 @@ export const getAll = ({ selectionSet: t.selectionSet({ selections: [ t.field({ - name: 'totalCount', + name: 'totalCount' }), t.field({ name: 'nodes', - selectionSet: t.selectionSet({ selections }), - }), - ], - }), - }), + selectionSet: t.selectionSet({ selections }) + }) + ] + }) + }) ]; const ast = t.document({ @@ -120,9 +119,9 @@ export const getAll = ({ t.operationDefinition({ operation: 'query', name: queryName, - selectionSet: t.selectionSet({ selections: opSel }), - }), - ], + selectionSet: t.selectionSet({ selections: opSel }) + }) + ] }); return ast; @@ -131,7 +130,7 @@ export const getAll = ({ export const getCount = ({ queryName, operationName, - query, + query }: Omit): DocumentNode => { const Singular = query.model; const Filter = `${Singular}Filter`; @@ -140,17 +139,17 @@ export const getCount = ({ const variableDefinitions: VariableDefinitionNode[] = [ t.variableDefinition({ variable: t.variable({ name: 'condition' }), - type: t.namedType({ type: Condition }), + type: t.namedType({ type: Condition }) }), t.variableDefinition({ variable: t.variable({ name: 'filter' }), - type: t.namedType({ type: Filter }), - }), + type: t.namedType({ type: Filter }) + }) ]; const args: ArgumentNode[] = [ t.argument({ name: 'condition', value: t.variable({ name: 'condition' }) }), - t.argument({ name: 'filter', value: t.variable({ name: 'filter' }) }), + t.argument({ name: 'filter', value: t.variable({ name: 'filter' }) }) ]; // PostGraphile supports totalCount through connections @@ -161,11 +160,11 @@ export const getCount = ({ selectionSet: t.selectionSet({ selections: [ t.field({ - name: 'totalCount', - }), - ], - }), - }), + name: 'totalCount' + }) + ] + }) + }) ]; const ast = t.document({ @@ -174,9 +173,9 @@ export const getCount = ({ operation: 'query', name: queryName, variableDefinitions, - selectionSet: t.selectionSet({ selections: opSel }), - }), - ], + selectionSet: t.selectionSet({ selections: opSel }) + }) + ] }); return ast; @@ -187,7 +186,7 @@ export const getMany = ({ queryName, operationName, query, - selection, + selection }: ASTFunctionParams): DocumentNode => { const Singular = query.model; const Plural = @@ -200,38 +199,38 @@ export const getMany = ({ const variableDefinitions: VariableDefinitionNode[] = [ t.variableDefinition({ variable: t.variable({ name: 'first' }), - type: t.namedType({ type: 'Int' }), + type: t.namedType({ type: 'Int' }) }), t.variableDefinition({ variable: t.variable({ name: 'last' }), - type: t.namedType({ type: 'Int' }), + type: t.namedType({ type: 'Int' }) }), t.variableDefinition({ variable: t.variable({ name: 'after' }), - type: t.namedType({ type: 'Cursor' }), + type: t.namedType({ type: 'Cursor' }) }), t.variableDefinition({ variable: t.variable({ name: 'before' }), - type: t.namedType({ type: 'Cursor' }), + type: t.namedType({ type: 'Cursor' }) }), t.variableDefinition({ variable: t.variable({ name: 'offset' }), - type: t.namedType({ type: 'Int' }), + type: t.namedType({ type: 'Int' }) }), t.variableDefinition({ variable: t.variable({ name: 'condition' }), - type: t.namedType({ type: Condition }), + type: t.namedType({ type: Condition }) }), t.variableDefinition({ variable: t.variable({ name: 'filter' }), - type: t.namedType({ type: Filter }), + type: t.namedType({ type: Filter }) }), t.variableDefinition({ variable: t.variable({ name: 'orderBy' }), type: t.listType({ - type: t.nonNullType({ type: t.namedType({ type: OrderBy }) }), - }), - }), + type: t.nonNullType({ type: t.namedType({ type: OrderBy }) }) + }) + }) ]; const args: ArgumentNode[] = [ @@ -242,44 +241,44 @@ export const getMany = ({ t.argument({ name: 'before', value: t.variable({ name: 'before' }) }), t.argument({ name: 'condition', - value: t.variable({ name: 'condition' }), + value: t.variable({ name: 'condition' }) }), t.argument({ name: 'filter', value: t.variable({ name: 'filter' }) }), - t.argument({ name: 'orderBy', value: t.variable({ name: 'orderBy' }) }), + t.argument({ name: 'orderBy', value: t.variable({ name: 'orderBy' }) }) ]; const pageInfoFields: FieldNode[] = [ t.field({ name: 'hasNextPage' }), t.field({ name: 'hasPreviousPage' }), t.field({ name: 'endCursor' }), - t.field({ name: 'startCursor' }), + t.field({ name: 'startCursor' }) ]; const dataField: FieldNode = builder?._edges ? t.field({ - name: 'edges', - selectionSet: t.selectionSet({ - selections: [ - t.field({ name: 'cursor' }), - t.field({ - name: 'node', - selectionSet: t.selectionSet({ selections }), - }), - ], - }), + name: 'edges', + selectionSet: t.selectionSet({ + selections: [ + t.field({ name: 'cursor' }), + t.field({ + name: 'node', + selectionSet: t.selectionSet({ selections }) + }) + ] }) + }) : t.field({ - name: 'nodes', - selectionSet: t.selectionSet({ selections }), - }); + name: 'nodes', + selectionSet: t.selectionSet({ selections }) + }); const connectionFields: FieldNode[] = [ t.field({ name: 'totalCount' }), t.field({ name: 'pageInfo', - selectionSet: t.selectionSet({ selections: pageInfoFields }), + selectionSet: t.selectionSet({ selections: pageInfoFields }) }), - dataField, + dataField ]; const ast = t.document({ @@ -293,12 +292,12 @@ export const getMany = ({ t.field({ name: operationName, args, - selectionSet: t.selectionSet({ selections: connectionFields }), - }), - ], - }), - }), - ], + selectionSet: t.selectionSet({ selections: connectionFields }) + }) + ] + }) + }) + ] }); return ast; @@ -308,7 +307,7 @@ export const getOne = ({ queryName, operationName, query, - selection, + selection }: ASTFunctionParams): DocumentNode => { const variableDefinitions: VariableDefinitionNode[] = Object.keys( query.properties @@ -321,7 +320,7 @@ export const getOne = ({ type: fieldType, isNotNull, isArray, - isArrayNotNull, + isArrayNotNull } = field; let type: TypeNode = t.namedType({ type: fieldType }); if (isNotNull) type = t.nonNullType({ type }); @@ -331,7 +330,7 @@ export const getOne = ({ } return t.variableDefinition({ variable: t.variable({ name: fieldName }), - type, + type }); }); @@ -342,7 +341,7 @@ export const getOne = ({ .map((field) => { return t.argument({ name: field.name, - value: t.variable({ name: field.name }), + value: t.variable({ name: field.name }) }); }); @@ -352,8 +351,8 @@ export const getOne = ({ t.field({ name: operationName, args: selectArgs, - selectionSet: t.selectionSet({ selections }), - }), + selectionSet: t.selectionSet({ selections }) + }) ]; const ast = t.document({ @@ -362,9 +361,9 @@ export const getOne = ({ operation: 'query', name: queryName, variableDefinitions, - selectionSet: t.selectionSet({ selections: opSel }), - }), - ], + selectionSet: t.selectionSet({ selections: opSel }) + }) + ] }); return ast; }; @@ -373,7 +372,7 @@ export const createOne = ({ mutationName, operationName, mutation, - selection, + selection }: MutationASTParams): DocumentNode => { if (!mutation.properties?.input?.properties) { throw new Error(`No input field for mutation: ${mutationName}`); @@ -412,14 +411,14 @@ export const createOne = ({ fields: attrs.map((field) => t.objectField({ name: field.name, - value: t.variable({ name: field.name }), + value: t.variable({ name: field.name }) }) - ), - }), - }), - ], - }), - }), + ) + }) + }) + ] + }) + }) ]; const selections = selection @@ -432,7 +431,7 @@ export const createOne = ({ selectArgs, selections, variableDefinitions, - modelName, + modelName }); return ast; @@ -442,7 +441,7 @@ export const patchOne = ({ mutationName, operationName, mutation, - selection, + selection }: MutationASTParams): DocumentNode => { if (!mutation.properties?.input?.properties) { throw new Error(`No input field for mutation: ${mutationName}`); @@ -479,7 +478,7 @@ export const patchOne = ({ ...patchByAttrs.map((field) => t.objectField({ name: field.name, - value: t.variable({ name: field.name }), + value: t.variable({ name: field.name }) }) ), t.objectField({ @@ -490,14 +489,14 @@ export const patchOne = ({ .map((field) => t.objectField({ name: field.name, - value: t.variable({ name: field.name }), + value: t.variable({ name: field.name }) }) - ), - }), - }), - ], - }), - }), + ) + }) + }) + ] + }) + }) ]; const selections = selection @@ -510,7 +509,7 @@ export const patchOne = ({ selectArgs, selections, variableDefinitions, - modelName, + modelName }); return ast; @@ -519,7 +518,7 @@ export const patchOne = ({ export const deleteOne = ({ mutationName, operationName, - mutation, + mutation }: Omit): DocumentNode => { if (!mutation.properties?.input?.properties) { throw new Error(`No input field for mutation: ${mutationName}`); @@ -548,7 +547,7 @@ export const deleteOne = ({ } return t.variableDefinition({ variable: t.variable({ name: fieldName }), - type, + type }); } ); @@ -560,11 +559,11 @@ export const deleteOne = ({ fields: deleteAttrs.map((f) => t.objectField({ name: f.name, - value: t.variable({ name: f.name }), + value: t.variable({ name: f.name }) }) - ), - }), - }), + ) + }) + }) ]; // so we can support column select grants plugin @@ -576,7 +575,7 @@ export const deleteOne = ({ selections, useModel: false, variableDefinitions, - modelName, + modelName }); return ast; @@ -614,7 +613,7 @@ export function getSelections(selection: QueryFieldSelection[] = []): FieldNode[ const [argName, argValue] = variable; const argAst = t.argument({ name: argName, - value: getComplexValueAst(argValue), + value: getComplexValueAst(argValue) }); return argAst ? [...acc, argAst] : acc; }, @@ -627,19 +626,19 @@ export function getSelections(selection: QueryFieldSelection[] = []): FieldNode[ const selectionSet = isBelongTo ? t.selectionSet({ selections: subSelections }) : t.selectionSet({ - selections: [ - t.field({ name: 'totalCount' }), - t.field({ - name: 'nodes', - selectionSet: t.selectionSet({ selections: subSelections }), - }), - ], - }); + selections: [ + t.field({ name: 'totalCount' }), + t.field({ + name: 'nodes', + selectionSet: t.selectionSet({ selections: subSelections }) + }) + ] + }); return t.field({ name, args, - selectionSet, + selectionSet }); } else { return selectionAst(selectionDefn); @@ -670,7 +669,7 @@ function getComplexValueAst(value: unknown): ValueNode { // Handle arrays if (Array.isArray(value)) { return t.listValue({ - values: value.map((item) => getComplexValueAst(item)), + values: value.map((item) => getComplexValueAst(item)) }); } @@ -681,9 +680,9 @@ function getComplexValueAst(value: unknown): ValueNode { fields: Object.entries(obj).map(([key, val]) => t.objectField({ name: key, - value: getComplexValueAst(val), + value: getComplexValueAst(val) }) - ), + ) }); } @@ -699,7 +698,7 @@ function getCreateVariablesAst( type: fieldType, isNotNull, isArray, - isArrayNotNull, + isArrayNotNull } = field; let type: TypeNode = t.namedType({ type: fieldType }); if (isNotNull) type = t.nonNullType({ type }); @@ -709,7 +708,7 @@ function getCreateVariablesAst( } return t.variableDefinition({ variable: t.variable({ name: fieldName }), - type, + type }); }); } @@ -730,14 +729,14 @@ function getUpdateVariablesAst( } return t.variableDefinition({ variable: t.variable({ name: fieldName }), - type, + type }); }); const patcherVariables: VariableDefinitionNode[] = patchers.map((patcher) => { return t.variableDefinition({ variable: t.variable({ name: patcher }), - type: t.nonNullType({ type: t.namedType({ type: 'String' }) }), + type: t.nonNullType({ type: t.namedType({ type: 'String' }) }) }); }); diff --git a/graphql/codegen/src/core/codegen/babel-ast.ts b/graphql/codegen/src/core/codegen/babel-ast.ts index 9a189b2f7..0b981d4de 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 @@ -29,7 +29,7 @@ export const commentBlock = (value: string): t.CommentBlock => { value, start: null, end: null, - loc: null, + loc: null }; }; @@ -42,7 +42,7 @@ export const commentLine = (value: string): t.CommentLine => { value, start: null, end: null, - loc: null, + loc: null }; }; diff --git a/graphql/codegen/src/core/codegen/barrel.ts b/graphql/codegen/src/core/codegen/barrel.ts index 25d5a6fa6..dc11a6843 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, + hasValidPrimaryKey } from './utils'; -import { getOperationHookName } from './type-resolver'; /** * Helper to create export * from './module' statement @@ -46,7 +47,7 @@ export function generateQueriesBarrel(tables: CleanTable[]): string { addJSDocComment(statements[0], [ 'Query hooks barrel export', '@generated by @constructive-io/graphql-codegen', - 'DO NOT EDIT - changes will be overwritten', + 'DO NOT EDIT - changes will be overwritten' ]); } @@ -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}`)); } } @@ -81,7 +82,7 @@ export function generateMutationsBarrel(tables: CleanTable[]): string { addJSDocComment(statements[0], [ 'Mutation hooks barrel export', '@generated by @constructive-io/graphql-codegen', - 'DO NOT EDIT - changes will be overwritten', + 'DO NOT EDIT - changes will be overwritten' ]); } @@ -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; @@ -112,27 +112,18 @@ export function generateMainBarrel( const opts: MainBarrelOptions = options; const { - hasSchemaTypes = false, hasMutations = true, hasQueryKeys = false, hasMutationKeys = false, - hasInvalidation = false, + hasInvalidation = false } = opts; const tableNames = tables.map((tbl) => tbl.name).join(', '); 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')); @@ -185,7 +176,7 @@ export function generateMainBarrel( ' const { mutate } = useCreateCarMutation();', ' // ...', '}', - '```', + '```' ]); } @@ -224,7 +215,7 @@ export function generateRootBarrel(options: RootBarrelOptions = {}): string { if (statements.length > 0) { addJSDocComment(statements[0], [ 'Generated SDK - auto-generated, do not edit', - '@generated by @constructive-io/graphql-codegen', + '@generated by @constructive-io/graphql-codegen' ]); } @@ -277,7 +268,7 @@ export function generateCustomQueriesBarrel( addJSDocComment(statements[0], [ 'Query hooks barrel export', '@generated by @constructive-io/graphql-codegen', - 'DO NOT EDIT - changes will be overwritten', + 'DO NOT EDIT - changes will be overwritten' ]); } @@ -302,15 +293,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}`)); @@ -333,7 +324,7 @@ export function generateCustomMutationsBarrel( addJSDocComment(statements[0], [ 'Mutation hooks barrel export', '@generated by @constructive-io/graphql-codegen', - 'DO NOT EDIT - changes will be overwritten', + 'DO NOT EDIT - changes will be overwritten' ]); } diff --git a/graphql/codegen/src/core/codegen/client.ts b/graphql/codegen/src/core/codegen/client.ts index 809c6f513..483837da4 100644 --- a/graphql/codegen/src/core/codegen/client.ts +++ b/graphql/codegen/src/core/codegen/client.ts @@ -1,74 +1,58 @@ /** - * 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. + * Generates a configure()/getClient() singleton pattern that wraps the ORM client. + * React Query hooks use getClient() to delegate to ORM model methods. */ -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; -} - /** - * Find a template file path. - * Templates are at ./templates/ relative to this file in both src/ and dist/. + * Generate client.ts content - ORM client wrapper with configure/getClient */ -function findTemplateFile(templateName: string): string { - const templatePath = path.join(__dirname, 'templates', templateName); +export function generateClientFile(): string { + const header = getGeneratedFileHeader('ORM client wrapper for React Query hooks'); - if (fs.existsSync(templatePath)) { - return templatePath; - } + const code = ` +import { createClient } from '../orm'; +import type { OrmClientConfig } from '../orm/client'; - throw new Error( - `Could not find template file: ${templateName}. ` + - `Searched in: ${templatePath}` - ); -} +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; /** - * Read a template file and replace the header with generated file header + * 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 ' }, + * }); + * \`\`\` */ -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' - ); - - return content; +export function configure(config: OrmClientConfig): void { + client = createClient(config); } /** - * Generate client.ts content - * @param options - Generation options + * Get the configured ORM client instance + * @throws Error if configure() has not been called */ -export function generateClientFile( - options: GenerateClientFileOptions = {} -): string { - const { browserCompatible = true } = options; - - const templateName = browserCompatible - ? 'client.browser.ts' - : 'client.node.ts'; +export function getClient(): OrmClientInstance { + if (!client) { + throw new Error( + 'ORM client not configured. Call configure() before using hooks.' + ); + } + return client; +} +`; - return readTemplateFile( - templateName, - 'GraphQL client configuration and execution' - ); + return header + '\n' + code.trim() + '\n'; } diff --git a/graphql/codegen/src/core/codegen/custom-mutations.ts b/graphql/codegen/src/core/codegen/custom-mutations.ts index 2d9a10aef..ef4cc4b90 100644 --- a/graphql/codegen/src/core/codegen/custom-mutations.ts +++ b/graphql/codegen/src/core/codegen/custom-mutations.ts @@ -4,6 +4,9 @@ * 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 @@ -12,24 +15,21 @@ */ import type { CleanOperation, - CleanArgument, - TypeRegistry, + 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 { - typeRefToTsType, - isTypeRequired, - getOperationHookName, - getOperationFileName, - getOperationVariablesTypeName, - getOperationResultTypeName, - getDocumentConstName, + buildDefaultSelectLiteral, + getSelectTypeName, + wrapInferSelectResult +} from './select-helpers'; +import { createTypeTracker, - type TypeTracker, + getOperationFileName, + getOperationHookName, + getTypeBaseName, + typeRefToTsType } from './type-resolver'; -import { getGeneratedFileHeader } from './utils'; +import { getGeneratedFileHeader,ucFirst } from './utils'; export interface GeneratedCustomMutationFile { fileName: string; @@ -47,25 +47,6 @@ export interface GenerateCustomMutationHookOptions { 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 ): GeneratedCustomMutationFile | null { @@ -90,210 +71,147 @@ function generateCustomMutationHookInternal( const { operation, typeRegistry, - maxDepth = 2, - skipQueryField = true, tableTypeNames, - useCentralizedKeys = true, + 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 variablesProps = - operation.args.length > 0 - ? generateVariablesProperties(operation.args, tracker) - : []; + const hasArgs = operation.args.length > 0; + // Resolve types using tracker for import tracking const resultType = typeRefToTsType(operation.returnType, tracker); - - const schemaTypes = tracker.getImportableTypes(); - const tableTypes = tracker.getTableTypes(); - - const reactQueryImport = t.importDeclaration( - [t.importSpecifier(t.identifier('useMutation'), t.identifier('useMutation'))], - 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') - ); - reactQueryTypeImport.importKind = 'type'; - statements.push(reactQueryTypeImport); - - const clientImport = t.importDeclaration( - [t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], - t.stringLiteral('../client') - ); - 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') - ); - 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') - ); - schemaTypesImport.importKind = 'type'; - statements.push(schemaTypesImport); - } - - if (useCentralizedKeys) { - const mutationKeyImport = t.importDeclaration( - [t.importSpecifier(t.identifier('customMutationKeys'), t.identifier('customMutationKeys'))], - t.stringLiteral('../mutation-keys') - ); - 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) - ); - statements.push(t.exportNamedDeclaration(variablesInterface)); + for (const arg of operation.args) { + typeRefToTsType(arg.type, tracker); } - 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)); + const selectTypeName = getSelectTypeName(operation.returnType); + const payloadTypeName = getTypeBaseName(operation.returnType); + const hasSelect = !!selectTypeName && !!payloadTypeName; + const defaultSelectLiteral = + hasSelect && payloadTypeName + ? buildDefaultSelectLiteral(payloadTypeName, typeRegistry) + : null; - const hasArgs = operation.args.length > 0; + const lines: string[] = []; - const hookBodyStatements: t.Statement[] = []; - const mutationOptions: (t.ObjectProperty | t.SpreadElement)[] = []; + // Imports + lines.push(`import { useMutation } from '@tanstack/react-query';`); + lines.push(`import type { UseMutationOptions } from '@tanstack/react-query';`); + lines.push(`import { getClient } from '../client';`); if (useCentralizedKeys) { - mutationOptions.push( - t.objectProperty( - t.identifier('mutationKey'), - t.callExpression( - t.memberExpression(t.identifier('customMutationKeys'), t.identifier(operation.name)), - [] - ) - ) - ); + lines.push(`import { customMutationKeys } from '../mutation-keys';`); } + // ORM type imports - variable types come from orm/mutation, entity types from orm/input-types 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)), - ] - ) - ) - ) - ); + lines.push(`import type { ${varTypeName} } from '../../orm/mutation';`); + } + + const inputTypeImports: string[] = []; + if (hasSelect) { + inputTypeImports.push(selectTypeName); + inputTypeImports.push(payloadTypeName); } else { - mutationOptions.push( - t.objectProperty( - t.identifier('mutationFn'), - t.arrowFunctionExpression( - [], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(documentConstName)], - [t.tsTypeReference(t.identifier(resultTypeName))] - ) - ) - ) - ); + // For scalar/Connection returns, import any non-scalar type used in resultType + for (const refType of tracker.referencedTypes) { + if (!inputTypeImports.includes(refType)) { + inputTypeImports.push(refType); + } + } + } + if (inputTypeImports.length > 0) { + lines.push(`import type { ${inputTypeImports.join(', ')} } from '../../orm/input-types';`); } - mutationOptions.push(t.spreadElement(t.identifier('options'))); + if (hasSelect) { + lines.push(`import type { DeepExact, InferSelectResult } from '../../orm/select-types';`); + } - hookBodyStatements.push( - t.returnStatement( - t.callExpression(t.identifier('useMutation'), [t.objectExpression(mutationOptions)]) - ) - ); + lines.push(''); - const optionsType = hasArgs - ? `Omit, 'mutationFn'>` - : `Omit, 'mutationFn'>`; + // Re-export variable types for consumer convenience + if (hasArgs) { + lines.push(`export type { ${varTypeName} } from '../../orm/mutation';`); + } + if (hasSelect) { + lines.push(`export type { ${selectTypeName} } from '../../orm/input-types';`); + } + if (hasArgs || hasSelect) { + lines.push(''); + } - const optionsParam = t.identifier('options'); - optionsParam.optional = true; - optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(optionsType))); + if (hasSelect && defaultSelectLiteral) { + lines.push(`const defaultSelect = ${defaultSelectLiteral} as const;`); + lines.push(''); + } - const hookFunc = t.functionDeclaration( - t.identifier(hookName), - [optionsParam], - t.blockStatement(hookBodyStatements) - ); - const hookExport = t.exportNamedDeclaration(hookFunc); - statements.push(hookExport); + // Hook + if (hasSelect) { + // With select: generic hook + const selectedResult = wrapInferSelectResult(operation.returnType, payloadTypeName); + const resultTypeStr = `{ ${operation.name}: ${selectedResult} }`; + const mutationVarType = hasArgs ? varTypeName : 'void'; + + const optionsType = `Omit, 'mutationFn'>`; + + lines.push(`export function ${hookName}(`); + lines.push(` args?: { select?: DeepExact },`); + lines.push(` options?: ${optionsType}`); + lines.push(`) {`); + lines.push(` return useMutation({`); + + if (useCentralizedKeys) { + lines.push(` mutationKey: customMutationKeys.${operation.name}(),`); + } + + if (hasArgs) { + lines.push(` mutationFn: (variables: ${varTypeName}) => getClient().mutation.${operation.name}(variables, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); + } else { + lines.push(` mutationFn: () => getClient().mutation.${operation.name}({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); + } + + lines.push(` ...options,`); + lines.push(` });`); + lines.push(`}`); + } else { + // Without select: simple hook (scalar return type) + const resultTypeStr = `{ ${operation.name}: ${resultType} }`; + const mutationVarType = hasArgs ? varTypeName : 'void'; + + const optionsType = `Omit, 'mutationFn'>`; + + lines.push(`export function ${hookName}(`); + lines.push(` options?: ${optionsType}`); + lines.push(`) {`); + lines.push(` return useMutation({`); + + if (useCentralizedKeys) { + lines.push(` mutationKey: customMutationKeys.${operation.name}(),`); + } + + if (hasArgs) { + lines.push(` mutationFn: (variables: ${varTypeName}) => getClient().mutation.${operation.name}(variables).unwrap(),`); + } else { + lines.push(` mutationFn: () => getClient().mutation.${operation.name}().unwrap(),`); + } + + lines.push(` ...options,`); + lines.push(` });`); + lines.push(`}`); + } - const code = generateCode(statements); - const content = getGeneratedFileHeader(`Custom mutation hook for ${operation.name}`) + '\n\n' + code; + const content = getGeneratedFileHeader(`Custom mutation hook for ${operation.name}`) + '\n\n' + lines.join('\n') + '\n'; return { fileName, content, - operationName: operation.name, + operationName: operation.name }; } @@ -317,7 +235,7 @@ export function generateAllCustomMutationHooks( skipQueryField = true, reactQueryEnabled = true, tableTypeNames, - useCentralizedKeys = true, + useCentralizedKeys = true } = options; return operations @@ -330,7 +248,7 @@ export function generateAllCustomMutationHooks( skipQueryField, reactQueryEnabled, tableTypeNames, - useCentralizedKeys, + 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..9c005c5e1 100644 --- a/graphql/codegen/src/core/codegen/custom-queries.ts +++ b/graphql/codegen/src/core/codegen/custom-queries.ts @@ -4,6 +4,9 @@ * 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 @@ -12,25 +15,23 @@ */ import type { CleanOperation, - CleanArgument, - TypeRegistry, + 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 { - typeRefToTsType, - isTypeRequired, - getOperationHookName, + buildDefaultSelectLiteral, + getSelectTypeName, + wrapInferSelectResult +} 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 { getGeneratedFileHeader,ucFirst } from './utils'; export interface GeneratedCustomQueryFile { fileName: string; @@ -48,497 +49,330 @@ export interface GenerateCustomQueryHookOptions { 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 ): GeneratedCustomQueryFile { const { operation, typeRegistry, - maxDepth = 2, - skipQueryField = true, reactQueryEnabled = true, tableTypeNames, - useCentralizedKeys = true, + useCentralizedKeys = true } = options; 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)); + // Resolve types using tracker for import tracking 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 defaultSelectLiteral = + hasSelect && payloadTypeName + ? buildDefaultSelectLiteral(payloadTypeName, typeRegistry) + : null; - const schemaTypes = tracker.getImportableTypes(); - const tableTypes = tracker.getTableTypes(); + const lines: string[] = []; + // Imports if (reactQueryEnabled) { - const reactQueryImport = t.importDeclaration( - [t.importSpecifier(t.identifier('useQuery'), t.identifier('useQuery'))], - t.stringLiteral('@tanstack/react-query') - ); - 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') - ); - reactQueryTypeImport.importKind = 'type'; - statements.push(reactQueryTypeImport); + lines.push(`import { useQuery } from '@tanstack/react-query';`); + lines.push(`import type { UseQueryOptions, QueryClient } from '@tanstack/react-query';`); } - 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') - ); - 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') - ); - typesImport.importKind = 'type'; - statements.push(typesImport); + lines.push(`import { getClient } from '../client';`); + + if (useCentralizedKeys) { + lines.push(`import { customQueryKeys } from '../query-keys';`); } - if (schemaTypes.length > 0) { - const schemaTypesImport = t.importDeclaration( - schemaTypes.map((st) => t.importSpecifier(t.identifier(st), t.identifier(st))), - t.stringLiteral('../schema-types') - ); - schemaTypesImport.importKind = 'type'; - statements.push(schemaTypesImport); + // ORM type imports - variable types come from orm/query, entity types from orm/input-types + if (hasArgs) { + lines.push(`import type { ${varTypeName} } from '../../orm/query';`); } - if (useCentralizedKeys) { - const queryKeyImport = t.importDeclaration( - [t.importSpecifier(t.identifier('customQueryKeys'), t.identifier('customQueryKeys'))], - t.stringLiteral('../query-keys') - ); - statements.push(queryKeyImport); + const inputTypeImports: string[] = []; + if (hasSelect) { + inputTypeImports.push(selectTypeName); + inputTypeImports.push(payloadTypeName); + } else { + // For scalar/Connection returns, import any non-scalar type used in resultType + const baseName = getTypeBaseName(operation.returnType); + if (baseName && !tracker.referencedTypes.has('__skip__')) { + // Import Connection types and other non-scalar types referenced in the result + for (const refType of tracker.referencedTypes) { + if (!inputTypeImports.includes(refType)) { + inputTypeImports.push(refType); + } + } + } + } + if (inputTypeImports.length > 0) { + lines.push(`import type { ${inputTypeImports.join(', ')} } from '../../orm/input-types';`); } - 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) - ); - statements.push(t.exportNamedDeclaration(variablesInterface)); + if (hasSelect) { + lines.push(`import type { DeepExact, InferSelectResult } from '../../orm/select-types';`); } - 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)); + lines.push(''); + // Re-export variable types for consumer convenience + if (hasArgs) { + lines.push(`export type { ${varTypeName} } from '../../orm/query';`); + } + if (hasSelect) { + lines.push(`export type { ${selectTypeName} } from '../../orm/input-types';`); + } + if (hasArgs || hasSelect) { + lines.push(''); + } + + if (hasSelect && defaultSelectLiteral) { + lines.push(`const defaultSelect = ${defaultSelectLiteral} as const;`); + lines.push(''); + } + + // 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 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); + lines.push(`/** Query key factory - re-exported from query-keys.ts */`); + lines.push(`export const ${queryKeyName} = customQueryKeys.${operation.name};`); + } else if (hasArgs) { + lines.push(`/** Query key factory for caching */`); + lines.push(`export const ${queryKeyName} = (variables?: ${varTypeName}) => ['${operation.name}', variables] as const;`); } else { - const queryKeyArrow = t.arrowFunctionExpression( - [], - t.tsAsExpression( - t.arrayExpression([t.stringLiteral(operation.name)]), - t.tsTypeReference(t.identifier('const')) - ) - ); - 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); + lines.push(`/** Query key factory for caching */`); + lines.push(`export const ${queryKeyName} = () => ['${operation.name}'] as const;`); } + lines.push(''); + // 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 ? `${hookName}({ ${argNames} })` : `${hookName}()`; - const hookBodyStatements: t.Statement[] = []; - const useQueryOptions: (t.ObjectProperty | t.SpreadElement)[] = []; + lines.push(`/**`); + lines.push(` * ${description}`); + lines.push(` *`); + lines.push(` * @example`); + lines.push(` * \`\`\`tsx`); + lines.push(` * const { data, isLoading } = ${exampleCall};`); + lines.push(` *`); + lines.push(` * if (data?.${operation.name}) {`); + lines.push(` * console.log(data.${operation.name});`); + lines.push(` * }`); + lines.push(` * \`\`\``); + lines.push(` */`); + + if (hasSelect) { + // With select: generic hook + const selectedResult = wrapInferSelectResult(operation.returnType, payloadTypeName); + const resultTypeStr = `{ ${operation.name}: ${selectedResult} }`; + const paramsArr: string[] = []; + + if (hasArgs) { + paramsArr.push(` variables${hasRequiredArgs ? '' : '?'}: ${varTypeName},`); + } + paramsArr.push(` args?: { select?: DeepExact },`); + + const optionsType = `Omit, 'queryKey' | 'queryFn'>`; + paramsArr.push(` options?: ${optionsType}`); + + lines.push(`export function ${hookName}(`); + lines.push(paramsArr.join('\n')); + lines.push(`) {`); + lines.push(` return useQuery({`); + + if (hasArgs) { + lines.push(` queryKey: ${queryKeyName}(variables),`); + lines.push(` queryFn: () => getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); + } else { + lines.push(` queryKey: ${queryKeyName}(),`); + lines.push(` queryFn: () => getClient().query.${operation.name}({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); + } - if (hasArgs) { - useQueryOptions.push( - t.objectProperty( - t.identifier('queryKey'), - t.callExpression(t.identifier(queryKeyName), [t.identifier('variables')]) - ) - ); - 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)), - ] - ) - ) - ) - ); if (hasRequiredArgs) { - useQueryOptions.push( - t.objectProperty( - t.identifier('enabled'), - t.logicalExpression( - '&&', - t.unaryExpression('!', t.unaryExpression('!', t.identifier('variables'))), - t.binaryExpression( - '!==', - t.optionalMemberExpression( - t.identifier('options'), - t.identifier('enabled'), - false, - true - ), - t.booleanLiteral(false) - ) - ) - ) - ); + lines.push(` enabled: !!variables && options?.enabled !== false,`); } + + lines.push(` ...options,`); + lines.push(` });`); + lines.push(`}`); } else { - useQueryOptions.push( - t.objectProperty( - t.identifier('queryKey'), - t.callExpression(t.identifier(queryKeyName), []) - ) - ); - useQueryOptions.push( - t.objectProperty( - t.identifier('queryFn'), - t.arrowFunctionExpression( - [], - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(documentConstName)], - [t.tsTypeReference(t.identifier(resultTypeName))] - ) - ) - ) - ); - } - useQueryOptions.push(t.spreadElement(t.identifier('options'))); + // Without select: simple hook (scalar return type) + const resultTypeStr = `{ ${operation.name}: ${resultType} }`; + const paramsArr: string[] = []; - hookBodyStatements.push( - t.returnStatement( - t.callExpression(t.identifier('useQuery'), [t.objectExpression(useQueryOptions)]) - ) - ); + if (hasArgs) { + paramsArr.push(` variables${hasRequiredArgs ? '' : '?'}: ${varTypeName},`); + } - const hookParams: t.Identifier[] = []; - if (hasArgs) { - hookParams.push( - typedParam('variables', t.tsTypeReference(t.identifier(variablesTypeName)), !hasRequiredArgs) - ); + const optionsType = `Omit, 'queryKey' | 'queryFn'>`; + paramsArr.push(` options?: ${optionsType}`); + + lines.push(`export function ${hookName}(`); + lines.push(paramsArr.join('\n')); + lines.push(`) {`); + lines.push(` return useQuery({`); + + if (hasArgs) { + lines.push(` queryKey: ${queryKeyName}(variables),`); + lines.push(` queryFn: () => getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}).unwrap(),`); + } else { + lines.push(` queryKey: ${queryKeyName}(),`); + lines.push(` queryFn: () => getClient().query.${operation.name}().unwrap(),`); + } + + if (hasRequiredArgs) { + lines.push(` enabled: !!variables && options?.enabled !== false,`); + } + + lines.push(` ...options,`); + lines.push(` });`); + lines.push(`}`); } - 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) - ); - 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, - '', - '@example', - '```tsx', - `const { data, isLoading } = ${exampleCall};`, - '', - `if (data?.${operation.name}) {`, - ` console.log(data.${operation.name});`, - '}', - '```', - ]); - statements.push(hookExport); + lines.push(''); } + // Fetch function (non-hook) const fetchFnName = `fetch${ucFirst(operation.name)}Query`; - const hasArgs = operation.args.length > 0; - const hasRequiredArgs = operation.args.some((arg) => isTypeRequired(arg.type)); + const fetchArgNames = operation.args.map((a) => a.name).join(', '); + const fetchExampleCall = hasArgs ? `${fetchFnName}({ ${fetchArgNames} })` : `${fetchFnName}()`; + + lines.push(`/**`); + lines.push(` * Fetch ${operation.name} without React hooks`); + lines.push(` *`); + lines.push(` * @example`); + lines.push(` * \`\`\`ts`); + lines.push(` * const data = await ${fetchExampleCall};`); + lines.push(` * \`\`\``); + lines.push(` */`); + + if (hasSelect) { + const fetchParamsArr: string[] = []; + if (hasArgs) { + fetchParamsArr.push(`variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}`); + } + fetchParamsArr.push(`args?: { select?: DeepExact }`); - 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)), - ] - ) - ) - ); + lines.push(`export async function ${fetchFnName}(`); + lines.push(` ${fetchParamsArr.join(',\n ')}`); + lines.push(`) {`); + if (hasArgs) { + lines.push(` return getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap();`); + } else { + lines.push(` return getClient().query.${operation.name}({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap();`); + } + lines.push(`}`); } else { - fetchBodyStatements.push( - t.returnStatement( - createTypedCallExpression( - t.identifier('execute'), - [t.identifier(documentConstName), t.identifier('undefined'), t.identifier('options')], - [t.tsTypeReference(t.identifier(resultTypeName))] - ) - ) - ); - } + const fetchParamsArr: string[] = []; + if (hasArgs) { + fetchParamsArr.push(`variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}`); + } - const fetchParams: t.Identifier[] = []; - if (hasArgs) { - fetchParams.push( - typedParam('variables', t.tsTypeReference(t.identifier(variablesTypeName)), !hasRequiredArgs) - ); + lines.push(`export async function ${fetchFnName}(`); + lines.push(` ${fetchParamsArr.join(',\n ')}`); + lines.push(`) {`); + if (hasArgs) { + lines.push(` return getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}).unwrap();`); + } else { + lines.push(` return getClient().query.${operation.name}().unwrap();`); + } + lines.push(`}`); } - 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) { + lines.push(''); + const prefetchFnName = `prefetch${ucFirst(operation.name)}Query`; + const prefetchArgNames = operation.args.map((a) => a.name).join(', '); + const prefetchExampleCall = hasArgs + ? `${prefetchFnName}(queryClient, { ${prefetchArgNames} })` + : `${prefetchFnName}(queryClient)`; - const prefetchBodyStatements: t.Statement[] = []; - const prefetchQueryOptions: t.ObjectProperty[] = []; + lines.push(`/**`); + lines.push(` * Prefetch ${operation.name} for SSR or cache warming`); + lines.push(` *`); + lines.push(` * @example`); + lines.push(` * \`\`\`ts`); + lines.push(` * await ${prefetchExampleCall};`); + lines.push(` * \`\`\``); + lines.push(` */`); + + if (hasSelect) { + const prefetchParamsArr: string[] = ['queryClient: QueryClient']; + if (hasArgs) { + prefetchParamsArr.push(`variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}`); + } + prefetchParamsArr.push(`args?: { select?: DeepExact }`); + + lines.push(`export async function ${prefetchFnName}(`); + lines.push(` ${prefetchParamsArr.join(',\n ')}`); + lines.push(`): Promise {`); + + if (hasArgs) { + lines.push(` await queryClient.prefetchQuery({`); + lines.push(` queryKey: ${queryKeyName}(variables),`); + lines.push(` queryFn: () => getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); + lines.push(` });`); + } else { + lines.push(` await queryClient.prefetchQuery({`); + lines.push(` queryKey: ${queryKeyName}(),`); + lines.push(` queryFn: () => getClient().query.${operation.name}({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); + lines.push(` });`); + } - if (hasArgs) { - prefetchQueryOptions.push( - t.objectProperty( - t.identifier('queryKey'), - t.callExpression(t.identifier(queryKeyName), [t.identifier('variables')]) - ) - ); - 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)), - ] - ) - ) - ) - ); + lines.push(`}`); } else { - prefetchQueryOptions.push( - t.objectProperty( - t.identifier('queryKey'), - t.callExpression(t.identifier(queryKeyName), []) - ) - ); - 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))] - ) - ) - ) - ); - } + const prefetchParamsArr: string[] = ['queryClient: QueryClient']; + if (hasArgs) { + prefetchParamsArr.push(`variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}`); + } - prefetchBodyStatements.push( - t.expressionStatement( - t.awaitExpression( - t.callExpression( - t.memberExpression(t.identifier('queryClient'), t.identifier('prefetchQuery')), - [t.objectExpression(prefetchQueryOptions)] - ) - ) - ) - ); + lines.push(`export async function ${prefetchFnName}(`); + lines.push(` ${prefetchParamsArr.join(',\n ')}`); + lines.push(`): Promise {`); + + if (hasArgs) { + lines.push(` await queryClient.prefetchQuery({`); + lines.push(` queryKey: ${queryKeyName}(variables),`); + lines.push(` queryFn: () => getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}).unwrap(),`); + lines.push(` });`); + } else { + lines.push(` await queryClient.prefetchQuery({`); + lines.push(` queryKey: ${queryKeyName}(),`); + lines.push(` queryFn: () => getClient().query.${operation.name}().unwrap(),`); + lines.push(` });`); + } - const prefetchParams: t.Identifier[] = [ - typedParam('queryClient', t.tsTypeReference(t.identifier('QueryClient'))), - ]; - if (hasArgs) { - prefetchParams.push( - typedParam('variables', t.tsTypeReference(t.identifier(variablesTypeName)), !hasRequiredArgs) - ); + lines.push(`}`); } - 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 = getGeneratedFileHeader(headerText) + '\n\n' + lines.join('\n') + '\n'; return { fileName, content, - operationName: operation.name, + operationName: operation.name }; } @@ -562,7 +396,7 @@ export function generateAllCustomQueryHooks( skipQueryField = true, reactQueryEnabled = true, tableTypeNames, - useCentralizedKeys = true, + useCentralizedKeys = true } = options; return operations @@ -575,7 +409,7 @@ export function generateAllCustomQueryHooks( skipQueryField, reactQueryEnabled, tableTypeNames, - useCentralizedKeys, + 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/index.ts b/graphql/codegen/src/core/codegen/index.ts index 407e10527..b77bad93d 100644 --- a/graphql/codegen/src/core/codegen/index.ts +++ b/graphql/codegen/src/core/codegen/index.ts @@ -2,52 +2,48 @@ * 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 { GraphQLSDKConfigTarget, QueryKeyConfig } from '../../types/config'; +import { DEFAULT_QUERY_KEY_CONFIG } from '../../types/config'; import type { - CleanTable, CleanOperation, - TypeRegistry, + 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 { getTableNames } from './utils'; // ============================================================================ @@ -114,7 +110,7 @@ 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 @@ -127,62 +123,18 @@ export function generate(options: GenerateOptions): GenerateResult { 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() }); // 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; @@ -190,11 +142,11 @@ export function generate(options: GenerateOptions): GenerateResult { const queryKeysResult = generateQueryKeysFile({ tables, customQueries: customOperations?.queries ?? [], - config: queryKeyConfig, + config: queryKeyConfig }); files.push({ path: queryKeysResult.fileName, - content: queryKeysResult.content, + content: queryKeysResult.content }); hasQueryKeys = true; } @@ -205,11 +157,11 @@ export function generate(options: GenerateOptions): GenerateResult { const mutationKeysResult = generateMutationKeysFile({ tables, customMutations: customOperations?.mutations ?? [], - config: queryKeyConfig, + config: queryKeyConfig }); files.push({ path: mutationKeysResult.fileName, - content: mutationKeysResult.content, + content: mutationKeysResult.content }); hasMutationKeys = true; } @@ -219,11 +171,11 @@ export function generate(options: GenerateOptions): GenerateResult { if (useCentralizedKeys && queryKeyConfig.generateCascadeHelpers) { const invalidationResult = generateInvalidationFile({ tables, - config: queryKeyConfig, + config: queryKeyConfig }); files.push({ path: invalidationResult.fileName, - content: invalidationResult.content, + content: invalidationResult.content }); hasInvalidation = true; } @@ -232,12 +184,12 @@ export function generate(options: GenerateOptions): GenerateResult { const queryHooks = generateAllQueryHooks(tables, { reactQueryEnabled, useCentralizedKeys, - hasRelationships, + hasRelationships }); for (const hook of queryHooks) { files.push({ path: `queries/${hook.fileName}`, - content: hook.content, + content: hook.content }); } @@ -255,13 +207,13 @@ export function generate(options: GenerateOptions): GenerateResult { skipQueryField, reactQueryEnabled, tableTypeNames, - useCentralizedKeys, + useCentralizedKeys }); for (const hook of customQueryHooks) { files.push({ path: `queries/${hook.fileName}`, - content: hook.content, + content: hook.content }); } } @@ -272,24 +224,21 @@ export function generate(options: GenerateOptions): GenerateResult { content: customQueryHooks.length > 0 ? generateCustomQueriesBarrel( - tables, - customQueryHooks.map((h) => h.operationName) - ) - : generateQueriesBarrel(tables), + tables, + customQueryHooks.map((h) => h.operationName) + ) + : generateQueriesBarrel(tables) }); // 6. Generate table-based mutation hooks (mutations/*.ts) const mutationHooks = generateAllMutationHooks(tables, { reactQueryEnabled, - enumsFromSchemaTypes: generatedEnumNames, - useCentralizedKeys, - hasRelationships, - tableTypeNames, + useCentralizedKeys }); for (const hook of mutationHooks) { files.push({ path: `mutations/${hook.fileName}`, - content: hook.content, + content: hook.content }); } @@ -307,13 +256,13 @@ export function generate(options: GenerateOptions): GenerateResult { skipQueryField, reactQueryEnabled, tableTypeNames, - useCentralizedKeys, + useCentralizedKeys }); for (const hook of customMutationHooks) { files.push({ path: `mutations/${hook.fileName}`, - content: hook.content, + content: hook.content }); } } @@ -328,23 +277,23 @@ export function generate(options: GenerateOptions): GenerateResult { content: customMutationHooks.length > 0 ? generateCustomMutationsBarrel( - tables, - customMutationHooks.map((h) => h.operationName) - ) - : generateMutationsBarrel(tables), + tables, + 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, - hasInvalidation, - }), + hasInvalidation + }) }); return { @@ -355,8 +304,8 @@ export function generate(options: GenerateOptions): GenerateResult { mutationHooks: mutationHooks.length, customQueryHooks: customQueryHooks.length, customMutationHooks: customMutationHooks.length, - totalFiles: files.length, - }, + totalFiles: files.length + } }; } @@ -364,34 +313,33 @@ export function generate(options: GenerateOptions): GenerateResult { // Re-exports for convenience // ============================================================================ +export { + generateCustomMutationsBarrel, + generateCustomQueriesBarrel, + generateMainBarrel, + generateMutationsBarrel, + generateQueriesBarrel +} from './barrel'; export { generateClientFile } from './client'; -export { generateTypesFile } from './types'; export { - generateAllQueryHooks, - generateListQueryHook, - generateSingleQueryHook, -} from './queries'; + generateAllCustomMutationHooks, + generateCustomMutationHook +} from './custom-mutations'; +export { + generateAllCustomQueryHooks, + generateCustomQueryHook +} from './custom-queries'; +export { generateInvalidationFile } from './invalidation'; +export { generateMutationKeysFile } from './mutation-keys'; export { generateAllMutationHooks, generateCreateMutationHook, - generateUpdateMutationHook, generateDeleteMutationHook, + generateUpdateMutationHook } from './mutations'; export { - generateAllCustomQueryHooks, - generateCustomQueryHook, -} from './custom-queries'; -export { - generateAllCustomMutationHooks, - generateCustomMutationHook, -} from './custom-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..ef9a5bf4b 100644 --- a/graphql/codegen/src/core/codegen/invalidation.ts +++ b/graphql/codegen/src/core/codegen/invalidation.ts @@ -4,17 +4,18 @@ * 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, - asConst, - typedParam, addLineComment, + asConst, + generateCode, + typedParam } from './babel-ast'; +import { getGeneratedFileHeader, getTableNames, lcFirst,ucFirst } from './utils'; export interface InvalidationGeneratorOptions { tables: CleanTable[]; @@ -247,7 +248,7 @@ function buildEntityInvalidateProperty( const withChildrenProp = t.objectProperty(t.identifier('withChildren'), withChildrenArrowFn); addJSDocComment(withChildrenProp, [ `Invalidate ${singularName} and all child entities`, - `Cascades to: ${descendants.join(', ')}`, + `Cascades to: ${descendants.join(', ')}` ]); innerProperties.push(withChildrenProp); } @@ -397,7 +398,7 @@ export function generateInvalidationFile( 'invalidate.user.lists(queryClient);', '', '// Invalidate specific user', - 'invalidate.user.detail(queryClient, userId);', + 'invalidate.user.detail(queryClient, userId);' ]; if (generateCascadeHelpers && Object.keys(relationships).length > 0) { invalidateDocLines.push(''); @@ -426,7 +427,7 @@ export function generateInvalidationFile( 'Remove queries from cache (for delete operations)', '', 'Use these when an entity is deleted to remove it from cache', - 'instead of just invalidating (which would trigger a refetch).', + 'instead of just invalidating (which would trigger a refetch).' ]); statements.push(removeDecl); @@ -484,6 +485,6 @@ ${description} return { fileName: 'invalidation.ts', - content, + content }; } diff --git a/graphql/codegen/src/core/codegen/mutation-keys.ts b/graphql/codegen/src/core/codegen/mutation-keys.ts index 431d84fe3..5816e3ee1 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, - typedParam, + generateCode, + typedParam } from './babel-ast'; +import { getGeneratedFileHeader, getTableNames, lcFirst } from './utils'; export interface MutationKeyGeneratorOptions { tables: CleanTable[]; @@ -75,12 +76,12 @@ function generateEntityMutationKeysDeclaration( false, true ) - ]), + ]) ]), constArray([ t.stringLiteral('mutation'), t.stringLiteral(entityKey), - t.stringLiteral('create'), + t.stringLiteral('create') ]) ) ); @@ -92,7 +93,7 @@ function generateEntityMutationKeysDeclaration( constArray([ t.stringLiteral('mutation'), t.stringLiteral(entityKey), - t.stringLiteral('create'), + t.stringLiteral('create') ]) ); @@ -108,7 +109,7 @@ function generateEntityMutationKeysDeclaration( t.stringLiteral('mutation'), t.stringLiteral(entityKey), t.stringLiteral('update'), - t.identifier('id'), + t.identifier('id') ]) ); const updateProp = t.objectProperty(t.identifier('update'), updateArrowFn); @@ -122,7 +123,7 @@ function generateEntityMutationKeysDeclaration( t.stringLiteral('mutation'), t.stringLiteral(entityKey), t.stringLiteral('delete'), - t.identifier('id'), + t.identifier('id') ]) ); const deleteProp = t.objectProperty(t.identifier('delete'), deleteArrowFn); @@ -166,7 +167,7 @@ function generateCustomMutationKeysDeclaration( constArray([ t.stringLiteral('mutation'), t.stringLiteral(op.name), - t.identifier('identifier'), + t.identifier('identifier') ]), constArray([t.stringLiteral('mutation'), t.stringLiteral(op.name)]) ) @@ -243,7 +244,7 @@ function generateUnifiedMutationStoreDeclaration( '', '// Check if a specific user is being updated', 'const isUpdating = useIsMutating({ mutationKey: mutationKeys.user.update(userId) });', - '```', + '```' ]); return decl; @@ -335,6 +336,6 @@ ${description} return { fileName: 'mutation-keys.ts', - content, + content }; } diff --git a/graphql/codegen/src/core/codegen/mutations.ts b/graphql/codegen/src/core/codegen/mutations.ts index 0a3a75227..8e368337e 100644 --- a/graphql/codegen/src/core/codegen/mutations.ts +++ b/graphql/codegen/src/core/codegen/mutations.ts @@ -1,51 +1,31 @@ /** - * Mutation hook generators using Babel AST-based code generation + * Mutation hook generators - delegates to ORM model methods * * 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 { - buildCreateMutationAST, - buildUpdateMutationAST, - buildDeleteMutationAST, - printGraphQL, -} from './gql-ast'; -import { - getTableNames, - getCreateMutationHookName, - getUpdateMutationHookName, - getDeleteMutationHookName, getCreateMutationFileName, - getUpdateMutationFileName, - getDeleteMutationFileName, + getCreateMutationHookName, getCreateMutationName, - getUpdateMutationName, + getDefaultSelectFieldName, + getDeleteMutationFileName, + getDeleteMutationHookName, getDeleteMutationName, - getScalarFields, - getPrimaryKeyInfo, - fieldTypeToTs, - ucFirst, - lcFirst, getGeneratedFileHeader, + getPrimaryKeyInfo, + getTableNames, + getUpdateMutationFileName, + getUpdateMutationHookName, + getUpdateMutationName, + hasValidPrimaryKey, + lcFirst } 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,11 +33,7 @@ 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; } export function generateCreateMutationHook( @@ -66,293 +42,95 @@ export function generateCreateMutationHook( ): GeneratedMutationFile | null { const { reactQueryEnabled = true, - enumsFromSchemaTypes = [], - useCentralizedKeys = true, - hasRelationships = false, - tableTypeNames = new Set(), + 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 selectTypeName = `${typeName}Select`; + const relationTypeName = `${typeName}WithRelations`; + const createInputTypeName = `Create${typeName}Input`; + + const defaultFieldName = getDefaultSelectFieldName(table); + + const lines: string[] = []; - const mutationAST = buildCreateMutationAST({ table }); - const mutationDocument = printGraphQL(mutationAST); - - 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') - ); - reactQueryTypeImport.importKind = 'type'; - statements.push(reactQueryTypeImport); - - const clientImport = t.importDeclaration( - [t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], - t.stringLiteral('../client') - ); - 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') - ); - 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); + // Imports + lines.push(`import { useMutation, useQueryClient } from '@tanstack/react-query';`); + lines.push(`import type { UseMutationOptions } from '@tanstack/react-query';`); + lines.push(`import { getClient } from '../client';`); + + if (useCentralizedKeys) { + lines.push(`import { ${keysName} } from '../query-keys';`); + lines.push(`import { ${mutationKeysName} } from '../mutation-keys';`); } + lines.push(`import type {`); + lines.push(` ${selectTypeName},`); + lines.push(` ${relationTypeName},`); + lines.push(` ${createInputTypeName},`); + lines.push(`} from '../../orm/input-types';`); + lines.push(`import type {`); + lines.push(` DeepExact,`); + lines.push(` InferSelectResult,`); + lines.push(`} from '../../orm/select-types';`); + lines.push(''); + + // Re-export types + lines.push(`export type { ${selectTypeName}, ${relationTypeName}, ${createInputTypeName} } from '../../orm/input-types';`); + lines.push(''); + + lines.push(`const defaultSelect = { ${defaultFieldName}: true } as const;`); + lines.push(''); + + // Hook + lines.push(`/**`); + lines.push(` * Mutation hook for creating a ${typeName}`); + lines.push(` *`); + lines.push(` * @example`); + lines.push(` * \`\`\`tsx`); + lines.push(` * const { mutate, isPending } = ${hookName}({`); + lines.push(` * select: { id: true, name: true },`); + lines.push(` * });`); + lines.push(` *`); + lines.push(` * mutate({ name: 'New item' });`); + lines.push(` * \`\`\``); + lines.push(` */`); + lines.push(`export function ${hookName}(`); + lines.push(` args?: { select?: DeepExact },`); + lines.push(` options?: Omit } }, Error, ${createInputTypeName}['${singularName}']>, 'mutationFn'>`); + lines.push(`) {`); + lines.push(` const queryClient = useQueryClient();`); + lines.push(` return useMutation({`); + 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(mutationKeyImport); + lines.push(` mutationKey: ${mutationKeysName}.create(),`); } - 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(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`))) - ), - ]) - ) - ), - ]); - 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))) - ), - ]) - ) - ), - ]); - 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)]) - ) - ); - - 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) - ); - const hookExport = t.exportNamedDeclaration(hookFunc); - addJSDocComment(hookExport, [ - `Mutation hook for creating a ${typeName}`, - '', - '@example', - '```tsx', - `const { mutate, isPending } = ${hookName}();`, - '', - 'mutate({', - ' input: {', - ` ${lcFirst(typeName)}: {`, - ' // ... fields', - ' },', - ' },', - '});', - '```', - ]); - statements.push(hookExport); - - const code = generateCode(statements); - const content = getGeneratedFileHeader(`Create mutation hook for ${typeName}`) + '\n\n' + code; + lines.push(` mutationFn: (data: ${createInputTypeName}['${singularName}']) => getClient().${singularName}.create({ data, select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); + + const listKey = useCentralizedKeys + ? `${keysName}.lists()` + : `['${typeName.toLowerCase()}', 'list']`; + lines.push(` onSuccess: () => {`); + lines.push(` queryClient.invalidateQueries({ queryKey: ${listKey} });`); + lines.push(` },`); + lines.push(` ...options,`); + lines.push(` });`); + lines.push(`}`); + + const content = getGeneratedFileHeader(`Create mutation hook for ${typeName}`) + '\n\n' + lines.join('\n') + '\n'; return { fileName: getCreateMutationFileName(table), - content, + content }; } @@ -362,10 +140,7 @@ export function generateUpdateMutationHook( ): GeneratedMutationFile | null { const { reactQueryEnabled = true, - enumsFromSchemaTypes = [], - useCentralizedKeys = true, - hasRelationships = false, - tableTypeNames = new Set(), + useCentralizedKeys = true } = options; if (!reactQueryEnabled) { @@ -376,307 +151,98 @@ export function generateUpdateMutationHook( return null; } - const enumSet = new Set(enumsFromSchemaTypes); + if (!hasValidPrimaryKey(table)) { + return null; + } + 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 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') - ); - reactQueryTypeImport.importKind = 'type'; - statements.push(reactQueryTypeImport); - - const clientImport = t.importDeclaration( - [t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], - t.stringLiteral('../client') - ); - 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') - ); - 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); - } + const lines: string[] = []; + + // Imports + lines.push(`import { useMutation, useQueryClient } from '@tanstack/react-query';`); + lines.push(`import type { UseMutationOptions } from '@tanstack/react-query';`); + lines.push(`import { getClient } from '../client';`); 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(mutationKeyImport); + lines.push(`import { ${keysName} } from '../query-keys';`); + lines.push(`import { ${mutationKeysName} } from '../mutation-keys';`); } - 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(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`))) - ), - ]) - ) - ), - ]); - 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))) - ), - ]) - ) - ), - ]); - 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)[] = []; + lines.push(`import type {`); + lines.push(` ${selectTypeName},`); + lines.push(` ${relationTypeName},`); + lines.push(` ${patchTypeName},`); + lines.push(`} from '../../orm/input-types';`); + lines.push(`import type {`); + lines.push(` DeepExact,`); + lines.push(` InferSelectResult,`); + lines.push(`} from '../../orm/select-types';`); + lines.push(''); + + // Re-export types + lines.push(`export type { ${selectTypeName}, ${relationTypeName}, ${patchTypeName} } from '../../orm/input-types';`); + lines.push(''); + + lines.push(`const defaultSelect = { ${pkField.name}: true } as const;`); + lines.push(''); + + // Hook + lines.push(`/**`); + lines.push(` * Mutation hook for updating a ${typeName}`); + lines.push(` *`); + lines.push(` * @example`); + lines.push(` * \`\`\`tsx`); + lines.push(` * const { mutate, isPending } = ${hookName}({`); + lines.push(` * select: { id: true, name: true },`); + lines.push(` * });`); + lines.push(` *`); + lines.push(` * mutate({ ${pkField.name}: 'value-here', patch: { name: 'Updated' } });`); + lines.push(` * \`\`\``); + lines.push(` */`); + lines.push(`export function ${hookName}(`); + lines.push(` args?: { select?: DeepExact },`); + lines.push(` options?: Omit } }, Error, { ${pkField.name}: ${pkField.tsType}; patch: ${patchTypeName} }>, 'mutationFn'>`); + lines.push(`) {`); + lines.push(` const queryClient = useQueryClient();`); + lines.push(` return useMutation({`); + if (useCentralizedKeys) { - mutationOptions.push( - t.objectProperty( - t.identifier('mutationKey'), - t.memberExpression(t.identifier(mutationKeysName), t.identifier('all')) - ) - ); + lines.push(` mutationKey: ${mutationKeysName}.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 detailQueryKey = useCentralizedKeys - ? t.callExpression( - t.memberExpression(t.identifier(keysName), t.identifier('detail')), - [t.memberExpression(t.memberExpression(t.identifier('variables'), t.identifier('input')), 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)), - ]); - - 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)])] - ) - ), - t.expressionStatement( - t.callExpression( - t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), - [t.objectExpression([t.objectProperty(t.identifier('queryKey'), listQueryKey)])] - ) - ), - ]) - ) - ) - ); - mutationOptions.push(t.spreadElement(t.identifier('options'))); - - hookBodyStatements.push( - t.returnStatement( - t.callExpression(t.identifier('useMutation'), [t.objectExpression(mutationOptions)]) - ) - ); - - 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) - ); - 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; + + lines.push(` mutationFn: ({ ${pkField.name}, patch }: { ${pkField.name}: ${pkField.tsType}; patch: ${patchTypeName} }) => getClient().${singularName}.update({ where: { ${pkField.name} }, data: patch, select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); + + const detailKey = useCentralizedKeys + ? `${keysName}.detail(variables.${pkField.name})` + : `['${typeName.toLowerCase()}', 'detail', variables.${pkField.name}]`; + const listKey = useCentralizedKeys + ? `${keysName}.lists()` + : `['${typeName.toLowerCase()}', 'list']`; + + lines.push(` onSuccess: (_, variables) => {`); + lines.push(` queryClient.invalidateQueries({ queryKey: ${detailKey} });`); + lines.push(` queryClient.invalidateQueries({ queryKey: ${listKey} });`); + lines.push(` },`); + lines.push(` ...options,`); + lines.push(` });`); + lines.push(`}`); + + const content = getGeneratedFileHeader(`Update mutation hook for ${typeName}`) + '\n\n' + lines.join('\n') + '\n'; return { fileName: getUpdateMutationFileName(table), - content, + content }; } @@ -686,8 +252,7 @@ export function generateDeleteMutationHook( ): GeneratedMutationFile | null { const { reactQueryEnabled = true, - useCentralizedKeys = true, - hasRelationships = false, + useCentralizedKeys = true } = options; if (!reactQueryEnabled) { @@ -698,233 +263,96 @@ export function generateDeleteMutationHook( return null; } - const { typeName } = getTableNames(table); + if (!hasValidPrimaryKey(table)) { + return null; + } + + 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 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') - ); - 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 lines: string[] = []; + + // Imports + lines.push(`import { useMutation, useQueryClient } from '@tanstack/react-query';`); + lines.push(`import type { UseMutationOptions } from '@tanstack/react-query';`); + lines.push(`import { getClient } from '../client';`); 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(mutationKeyImport); + lines.push(`import { ${keysName} } from '../query-keys';`); + lines.push(`import { ${mutationKeysName} } from '../mutation-keys';`); } - const mutationDocConst = t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier(`${mutationName}MutationDocument`), - t.templateLiteral( - [t.templateElement({ raw: '\n' + mutationDocument, cooked: '\n' + mutationDocument }, 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)), - ]) - ) - ), - ]); - 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()])) - ); - - const resultInterfaceBody = t.tsInterfaceBody([ - t.tsPropertySignature( - t.identifier(mutationName), - t.tsTypeAnnotation(t.tsTypeLiteral([clientMutationIdProp])) - ), - ]); - 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)[] = []; + lines.push(`import type {`); + lines.push(` ${selectTypeName},`); + lines.push(` ${relationTypeName},`); + lines.push(`} from '../../orm/input-types';`); + lines.push(`import type {`); + lines.push(` DeepExact,`); + lines.push(` InferSelectResult,`); + lines.push(`} from '../../orm/select-types';`); + lines.push(''); + + // Re-export types + lines.push(`export type { ${selectTypeName}, ${relationTypeName} } from '../../orm/input-types';`); + lines.push(''); + + lines.push(`const defaultSelect = { ${pkField.name}: true } as const;`); + lines.push(''); + + // Hook + lines.push(`/**`); + lines.push(` * Mutation hook for deleting a ${typeName}`); + lines.push(` *`); + lines.push(` * @example`); + lines.push(` * \`\`\`tsx`); + lines.push(` * const { mutate, isPending } = ${hookName}({`); + lines.push(` * select: { id: true },`); + lines.push(` * });`); + lines.push(` *`); + lines.push(` * mutate({ ${pkField.name}: ${pkField.tsType === 'string' ? "'value-to-delete'" : '123'} });`); + lines.push(` * \`\`\``); + lines.push(` */`); + lines.push(`export function ${hookName}(`); + lines.push(` args?: { select?: DeepExact },`); + lines.push(` options?: Omit } }, Error, { ${pkField.name}: ${pkField.tsType} }>, 'mutationFn'>`); + lines.push(`) {`); + lines.push(` const queryClient = useQueryClient();`); + lines.push(` return useMutation({`); + if (useCentralizedKeys) { - mutationOptions.push( - t.objectProperty( - t.identifier('mutationKey'), - t.memberExpression(t.identifier(mutationKeysName), t.identifier('all')) - ) - ); + lines.push(` mutationKey: ${mutationKeysName}.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 detailQueryKey = useCentralizedKeys - ? t.callExpression( - t.memberExpression(t.identifier(keysName), t.identifier('detail')), - [t.memberExpression(t.memberExpression(t.identifier('variables'), t.identifier('input')), 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)), - ]); - - 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)])] - ) - ), - t.expressionStatement( - t.callExpression( - t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), - [t.objectExpression([t.objectProperty(t.identifier('queryKey'), listQueryKey)])] - ) - ), - ]) - ) - ) - ); - mutationOptions.push(t.spreadElement(t.identifier('options'))); - - hookBodyStatements.push( - t.returnStatement( - t.callExpression(t.identifier('useMutation'), [t.objectExpression(mutationOptions)]) - ) - ); - - 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) - ); - 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; + + lines.push(` mutationFn: ({ ${pkField.name} }: { ${pkField.name}: ${pkField.tsType} }) => getClient().${singularName}.delete({ where: { ${pkField.name} }, select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); + + const detailKey = useCentralizedKeys + ? `${keysName}.detail(variables.${pkField.name})` + : `['${typeName.toLowerCase()}', 'detail', variables.${pkField.name}]`; + const listKey = useCentralizedKeys + ? `${keysName}.lists()` + : `['${typeName.toLowerCase()}', 'list']`; + + lines.push(` onSuccess: (_, variables) => {`); + lines.push(` queryClient.removeQueries({ queryKey: ${detailKey} });`); + lines.push(` queryClient.invalidateQueries({ queryKey: ${listKey} });`); + lines.push(` },`); + lines.push(` ...options,`); + lines.push(` });`); + lines.push(`}`); + + const content = getGeneratedFileHeader(`Delete mutation hook for ${typeName}`) + '\n\n' + lines.join('\n') + '\n'; return { fileName: getDeleteMutationFileName(table), - content, + content }; } diff --git a/graphql/codegen/src/core/codegen/orm/barrel.ts b/graphql/codegen/src/core/codegen/orm/barrel.ts index fda3b5b15..b1a9e63a0 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; @@ -41,7 +42,7 @@ export function generateModelsBarrel(tables: CleanTable[]): GeneratedBarrelFile return { fileName: 'models/index.ts', - content: header + '\n' + code, + content: header + '\n' + code }; } @@ -62,6 +63,6 @@ export * from './input-types'; return { fileName: 'types.ts', - content, + content }; } diff --git a/graphql/codegen/src/core/codegen/orm/client-generator.ts b/graphql/codegen/src/core/codegen/orm/client-generator.ts index 765d95807..293f0be52 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; @@ -61,7 +62,7 @@ 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') }; } @@ -76,7 +77,7 @@ export function generateQueryBuilderFile(): GeneratedClientFile { content: readTemplateFile( 'query-builder.ts', 'Query Builder - Builds and executes GraphQL operations' - ), + ) }; } @@ -88,7 +89,7 @@ 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') }; } @@ -167,7 +168,7 @@ export function generateCreateClientFile( t.exportSpecifier( t.identifier('GraphQLAdapter'), t.identifier('GraphQLAdapter') - ), + ) ], t.stringLiteral('./client') ); @@ -182,7 +183,7 @@ export function generateCreateClientFile( t.exportSpecifier( t.identifier('GraphQLRequestError'), t.identifier('GraphQLRequestError') - ), + ) ], t.stringLiteral('./client') ) @@ -196,7 +197,7 @@ export function generateCreateClientFile( t.exportSpecifier( t.identifier('QueryBuilder'), t.identifier('QueryBuilder') - ), + ) ], t.stringLiteral('./query-builder') ) @@ -217,7 +218,7 @@ export function generateCreateClientFile( t.exportSpecifier( t.identifier('createQueryOperations'), t.identifier('createQueryOperations') - ), + ) ], t.stringLiteral('./query') ) @@ -231,7 +232,7 @@ export function generateCreateClientFile( t.exportSpecifier( t.identifier('createMutationOperations'), t.identifier('createMutationOperations') - ), + ) ], t.stringLiteral('./mutation') ) @@ -257,7 +258,7 @@ export function generateCreateClientFile( t.objectProperty( t.identifier('query'), t.callExpression(t.identifier('createQueryOperations'), [ - t.identifier('client'), + t.identifier('client') ]) ) ); @@ -268,7 +269,7 @@ export function generateCreateClientFile( t.objectProperty( t.identifier('mutation'), t.callExpression(t.identifier('createMutationOperations'), [ - t.identifier('client'), + t.identifier('client') ]) ) ); @@ -279,7 +280,7 @@ export function generateCreateClientFile( t.variableDeclarator( t.identifier('client'), t.newExpression(t.identifier('OrmClient'), [t.identifier('config')]) - ), + ) ]); const returnStmt = t.returnStatement(t.objectExpression(returnProperties)); @@ -329,6 +330,6 @@ export function generateCreateClientFile( return { fileName: 'index.ts', - content: header + '\n' + code, + content: header + '\n' + code }; } diff --git a/graphql/codegen/src/core/codegen/orm/client.ts b/graphql/codegen/src/core/codegen/orm/client.ts index f7e233531..d217115f0 100644 --- a/graphql/codegen/src/core/codegen/orm/client.ts +++ b/graphql/codegen/src/core/codegen/orm/client.ts @@ -54,19 +54,19 @@ export class FetchAdapter implements GraphQLAdapter { headers: { 'Content-Type': 'application/json', Accept: 'application/json', - ...this.headers, + ...this.headers }, body: JSON.stringify({ query: document, - variables: variables ?? {}, - }), + variables: variables ?? {} + }) }); if (!response.ok) { return { ok: false, data: null, - errors: [{ message: `HTTP ${response.status}: ${response.statusText}` }], + errors: [{ message: `HTTP ${response.status}: ${response.statusText}` }] }; } @@ -79,14 +79,14 @@ export class FetchAdapter implements GraphQLAdapter { return { ok: false, data: null, - errors: json.errors, + errors: json.errors }; } return { ok: true, data: json.data as T, - errors: undefined, + errors: undefined }; } 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..e38554296 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 { generateCode } from '../babel-ast'; -import { ucFirst, getGeneratedFileHeader } from '../utils'; + +import type { CleanArgument, CleanOperation, TypeRegistry } from '../../../types/schema'; +import { asConst, generateCode } from '../babel-ast'; +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,13 +46,6 @@ 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 @@ -66,8 +60,6 @@ function collectPayloadTypeNamesFromOps( if ( baseName && !baseName.endsWith('Connection') && - baseName !== 'Query' && - baseName !== 'Mutation' && !NON_SELECT_TYPES.has(baseName) ) { payloadTypes.add(baseName); @@ -78,21 +70,26 @@ 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( @@ -153,15 +150,106 @@ 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 buildDefaultSelectExpression( + typeName: string, + typeRegistry: TypeRegistry, + depth: number = 0 +): t.Expression { + const resolved = typeRegistry.get(typeName); + const fields = resolved?.fields ?? []; + + if (depth > 3 || fields.length === 0) { + // Use first field if available, otherwise fallback to 'id' + const fallbackName = fields.length > 0 ? fields[0].name : 'id'; + return t.objectExpression([t.objectProperty(t.identifier(fallbackName), t.booleanLiteral(true))]); + } + + // Prefer id-like fields + const idLike = fields.find((f) => f.name === 'id' || f.name === 'nodeId'); + if (idLike) { + return t.objectExpression([ + t.objectProperty(t.identifier(idLike.name), t.booleanLiteral(true)) + ]); + } + + // Prefer scalar/enum fields + const scalarField = fields.find((f) => { + const baseName = getTypeBaseName(f.type); + if (!baseName) return false; + if (NON_SELECT_TYPES.has(baseName)) return true; + const baseResolved = typeRegistry.get(baseName); + return baseResolved?.kind === 'ENUM'; + }); + + if (scalarField) { + return t.objectExpression([ + t.objectProperty(t.identifier(scalarField.name), t.booleanLiteral(true)) + ]); + } + + // Fallback: first field (ensure valid selection for object fields) + const first = fields[0]; + + const firstBaseName = getTypeBaseName(first.type); + if (!firstBaseName || NON_SELECT_TYPES.has(firstBaseName)) { + return t.objectExpression([ + t.objectProperty(t.identifier(first.name), t.booleanLiteral(true)) + ]); + } + + const nestedResolved = typeRegistry.get(firstBaseName); + if (nestedResolved?.kind === 'ENUM') { + return t.objectExpression([ + t.objectProperty(t.identifier(first.name), t.booleanLiteral(true)) + ]); + } + + return t.objectExpression([ + t.objectProperty( + t.identifier(first.name), + t.objectExpression([ + t.objectProperty( + t.identifier('select'), + buildDefaultSelectExpression(firstBaseName, typeRegistry, depth + 1) + ) + ]) + ) + ]); +} + function buildOperationMethod( op: CleanOperation, - operationType: 'query' | 'mutation' + operationType: 'query' | 'mutation', + defaultSelectIdent?: t.Identifier ): t.ObjectProperty { const hasArgs = op.args.length > 0; const varTypeName = `${ucFirst(op.name)}Variables`; const varDefs = op.args.map((arg) => ({ name: arg.name, - type: formatGraphQLType(arg.type), + type: formatGraphQLType(arg.type) })); const selectTypeName = getSelectTypeName(op.returnType); @@ -191,14 +279,14 @@ function buildOperationMethod( t.identifier('DeepExact'), t.tsTypeParameterInstantiation([ t.tsTypeReference(t.identifier('S')), - t.tsTypeReference(t.identifier(selectTypeName)), + t.tsTypeReference(t.identifier(selectTypeName)) ]) ) ) ); prop.optional = true; return prop; - })(), + })() ]) ); } else { @@ -216,13 +304,21 @@ function buildOperationMethod( ); prop.optional = true; return prop; - })(), + })() ]) ); } params.push(optionsParam); // Build the QueryBuilder call + const selectExpr = defaultSelectIdent + ? t.logicalExpression( + '??', + t.optionalMemberExpression(t.identifier('options'), t.identifier('select'), false, true), + defaultSelectIdent + ) + : t.optionalMemberExpression(t.identifier('options'), t.identifier('select'), false, true); + const queryBuilderArgs = t.objectExpression([ t.objectProperty(t.identifier('client'), t.identifier('client'), false, true), t.objectProperty(t.identifier('operation'), t.stringLiteral(operationType)), @@ -233,39 +329,45 @@ function buildOperationMethod( 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.objectProperty(t.identifier('type'), t.stringLiteral(v.type)) ]) ) - ), + ) ]) - ), + ) ]); 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)) + ) + ]) ]); } @@ -273,9 +375,12 @@ function buildOperationMethod( // Add type parameters to arrow function if we have a select type if (selectTypeName) { + const defaultType = defaultSelectIdent + ? t.tsTypeQuery(defaultSelectIdent) + : null; const typeParam = t.tsTypeParameter( t.tsTypeReference(t.identifier(selectTypeName)), - null, + defaultType, 'S' ); (typeParam as any).const = true; @@ -289,7 +394,8 @@ function buildOperationMethod( * Generate the query/index.ts file for custom query operations */ export function generateCustomQueryOpsFile( - operations: CleanOperation[] + operations: CleanOperation[], + typeRegistry: TypeRegistry ): GeneratedCustomOpsFile { const statements: t.Statement[] = []; @@ -297,7 +403,8 @@ 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'])); @@ -314,8 +421,29 @@ export function generateCustomQueryOpsFile( if (varInterface) statements.push(varInterface); } + // Default selects (avoid invalid documents when select is omitted) + const defaultSelectIdentsByOpName = new Map(); + for (const op of operations) { + const selectTypeName = getSelectTypeName(op.returnType); + const payloadTypeName = getTypeBaseName(op.returnType); + if (!selectTypeName || !payloadTypeName) continue; + + const ident = t.identifier(`${op.name}DefaultSelect`); + defaultSelectIdentsByOpName.set(op.name, ident); + statements.push( + t.variableDeclaration('const', [ + t.variableDeclarator( + ident, + asConst(buildDefaultSelectExpression(payloadTypeName, typeRegistry)) + ) + ]) + ); + } + // Generate factory function - const operationProperties = operations.map((op) => buildOperationMethod(op, 'query')); + const operationProperties = operations.map((op) => + buildOperationMethod(op, 'query', defaultSelectIdentsByOpName.get(op.name)) + ); const returnObj = t.objectExpression(operationProperties); const returnStmt = t.returnStatement(returnObj); @@ -335,7 +463,7 @@ export function generateCustomQueryOpsFile( return { fileName: 'query/index.ts', - content: header + '\n' + code, + content: header + '\n' + code }; } @@ -343,7 +471,8 @@ export function generateCustomQueryOpsFile( * Generate the mutation/index.ts file for custom mutation operations */ export function generateCustomMutationOpsFile( - operations: CleanOperation[] + operations: CleanOperation[], + typeRegistry: TypeRegistry ): GeneratedCustomOpsFile { const statements: t.Statement[] = []; @@ -351,7 +480,8 @@ 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'])); @@ -368,8 +498,29 @@ export function generateCustomMutationOpsFile( if (varInterface) statements.push(varInterface); } + // Default selects (avoid invalid documents when select is omitted) + const defaultSelectIdentsByOpName = new Map(); + for (const op of operations) { + const selectTypeName = getSelectTypeName(op.returnType); + const payloadTypeName = getTypeBaseName(op.returnType); + if (!selectTypeName || !payloadTypeName) continue; + + const ident = t.identifier(`${op.name}DefaultSelect`); + defaultSelectIdentsByOpName.set(op.name, ident); + statements.push( + t.variableDeclaration('const', [ + t.variableDeclarator( + ident, + asConst(buildDefaultSelectExpression(payloadTypeName, typeRegistry)) + ) + ]) + ); + } + // Generate factory function - const operationProperties = operations.map((op) => buildOperationMethod(op, 'mutation')); + const operationProperties = operations.map((op) => + buildOperationMethod(op, 'mutation', defaultSelectIdentsByOpName.get(op.name)) + ); const returnObj = t.objectExpression(operationProperties); const returnStmt = t.returnStatement(returnObj); @@ -389,7 +540,7 @@ export function generateCustomMutationOpsFile( return { fileName: 'mutation/index.ts', - content: header + '\n' + code, + content: header + '\n' + code }; } diff --git a/graphql/codegen/src/core/codegen/orm/index.ts b/graphql/codegen/src/core/codegen/orm/index.ts index 099826959..afeff9380 100644 --- a/graphql/codegen/src/core/codegen/orm/index.ts +++ b/graphql/codegen/src/core/codegen/orm/index.ts @@ -4,21 +4,21 @@ * 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, + generateSelectTypesFile } 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; @@ -80,7 +80,7 @@ export function generateOrm(options: GenerateOrmOptions): GenerateOrmResult { for (const modelFile of modelFiles) { files.push({ path: `models/${modelFile.fileName}`, - content: modelFile.content, + content: modelFile.content }); } @@ -93,7 +93,7 @@ export function generateOrm(options: GenerateOrmOptions): GenerateOrmResult { if (tables.length > 0 || (typeRegistry && (hasCustomQueries || hasCustomMutations))) { const allOps = [ ...(customOperations?.queries ?? []), - ...(customOperations?.mutations ?? []), + ...(customOperations?.mutations ?? []) ]; const usedInputTypes = collectInputTypeNames(allOps); const usedPayloadTypes = collectPayloadTypeNames(allOps); @@ -106,7 +106,7 @@ export function generateOrm(options: GenerateOrmOptions): GenerateOrmResult { const crudPayloadTypes = [ `Create${typeName}Payload`, `Update${typeName}Payload`, - `Delete${typeName}Payload`, + `Delete${typeName}Payload` ]; for (const payloadType of crudPayloadTypes) { if (typeRegistry.has(payloadType)) { @@ -127,12 +127,18 @@ export function generateOrm(options: GenerateOrmOptions): GenerateOrmResult { // 5. Generate custom operations (if any) if (hasCustomQueries && customOperations?.queries) { - const queryOpsFile = generateCustomQueryOpsFile(customOperations.queries); + const queryOpsFile = generateCustomQueryOpsFile( + customOperations.queries, + typeRegistry ?? new Map() + ); files.push({ path: queryOpsFile.fileName, content: queryOpsFile.content }); } if (hasCustomMutations && customOperations?.mutations) { - const mutationOpsFile = generateCustomMutationOpsFile(customOperations.mutations); + const mutationOpsFile = generateCustomMutationOpsFile( + customOperations.mutations, + typeRegistry ?? new Map() + ); files.push({ path: mutationOpsFile.fileName, content: mutationOpsFile.content }); } @@ -150,17 +156,17 @@ export function generateOrm(options: GenerateOrmOptions): GenerateOrmResult { tables: tables.length, customQueries: customOperations?.queries.length ?? 0, customMutations: customOperations?.mutations.length ?? 0, - totalFiles: files.length, - }, + totalFiles: files.length + } }; } // Re-export generators for direct use +export { generateModelsBarrel, generateTypesBarrel } from './barrel'; export { generateOrmClientFile, generateQueryBuilderFile, - generateSelectTypesFile, + 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..ee3468f4f 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, - getOrderByTypeName, - isRelationField, + getFilterTypeName, getGeneratedFileHeader, + getOrderByTypeName, + getPrimaryKeyInfo, + getTableNames, + isRelationField } from '../utils'; -import { pluralize } from 'inflekt'; -import { getTypeBaseName } from '../type-resolver'; -import { scalarToTsType, scalarToFilterType } from '../scalars'; export interface GeneratedInputTypesFile { fileName: string; @@ -43,7 +45,7 @@ const EXCLUDED_MUTATION_FIELDS = [ 'id', 'createdAt', 'updatedAt', - 'nodeId', + 'nodeId' ] as const; // ============================================================================ @@ -54,7 +56,7 @@ const EXCLUDED_MUTATION_FIELDS = [ * Overrides for input-type generation */ const INPUT_SCALAR_OVERRIDES: Record = { - JSON: 'Record', + JSON: 'Record' }; /** @@ -63,7 +65,7 @@ const INPUT_SCALAR_OVERRIDES: Record = { function scalarToInputTs(scalar: string): string { return scalarToTsType(scalar, { unknownScalar: 'name', - overrides: INPUT_SCALAR_OVERRIDES, + overrides: INPUT_SCALAR_OVERRIDES }); } @@ -132,18 +134,18 @@ function parseTypeString(typeStr: string): t.TSType { // Handle primitive types switch (typeStr) { - case 'string': - return t.tsStringKeyword(); - case 'number': - return t.tsNumberKeyword(); - case 'boolean': - return t.tsBooleanKeyword(); - case 'null': - return t.tsNullKeyword(); - case 'unknown': - return t.tsUnknownKeyword(); - default: - return t.tsTypeReference(t.identifier(typeStr)); + case 'string': + return t.tsStringKeyword(); + case 'number': + return t.tsNumberKeyword(); + case 'boolean': + return t.tsBooleanKeyword(); + case 'null': + return t.tsNullKeyword(); + case 'unknown': + return t.tsUnknownKeyword(); + default: + return t.tsTypeReference(t.identifier(typeStr)); } } @@ -256,72 +258,72 @@ const SCALAR_FILTER_CONFIGS: ScalarFilterConfig[] = [ { name: 'StringFilter', tsType: 'string', - operators: ['equality', 'distinct', 'inArray', 'comparison', 'string'], + operators: ['equality', 'distinct', 'inArray', 'comparison', 'string'] }, { name: 'IntFilter', tsType: 'number', - operators: ['equality', 'distinct', 'inArray', 'comparison'], + operators: ['equality', 'distinct', 'inArray', 'comparison'] }, { name: 'FloatFilter', tsType: 'number', - operators: ['equality', 'distinct', 'inArray', 'comparison'], + operators: ['equality', 'distinct', 'inArray', 'comparison'] }, { name: 'BooleanFilter', tsType: 'boolean', operators: ['equality'] }, { name: 'UUIDFilter', tsType: 'string', - operators: ['equality', 'distinct', 'inArray'], + operators: ['equality', 'distinct', 'inArray'] }, { name: 'DatetimeFilter', tsType: 'string', - operators: ['equality', 'distinct', 'inArray', 'comparison'], + operators: ['equality', 'distinct', 'inArray', 'comparison'] }, { name: 'DateFilter', tsType: 'string', - operators: ['equality', 'distinct', 'inArray', 'comparison'], + operators: ['equality', 'distinct', 'inArray', 'comparison'] }, { name: 'JSONFilter', tsType: 'Record', - operators: ['equality', 'distinct', 'json'], + operators: ['equality', 'distinct', 'json'] }, { name: 'BigIntFilter', tsType: 'string', - operators: ['equality', 'distinct', 'inArray', 'comparison'], + operators: ['equality', 'distinct', 'inArray', 'comparison'] }, { name: 'BigFloatFilter', tsType: 'string', - operators: ['equality', 'distinct', 'inArray', 'comparison'], + operators: ['equality', 'distinct', 'inArray', 'comparison'] }, { name: 'BitStringFilter', tsType: 'string', operators: ['equality'] }, { name: 'InternetAddressFilter', tsType: 'string', - operators: ['equality', 'distinct', 'inArray', 'comparison', 'inet'], + operators: ['equality', 'distinct', 'inArray', 'comparison', 'inet'] }, { name: 'FullTextFilter', tsType: 'string', operators: ['fulltext'] }, // List filters (for array fields like string[], int[], uuid[]) { name: 'StringListFilter', tsType: 'string[]', - operators: ['equality', 'distinct', 'comparison', 'listArray'], + operators: ['equality', 'distinct', 'comparison', 'listArray'] }, { name: 'IntListFilter', tsType: 'number[]', - operators: ['equality', 'distinct', 'comparison', 'listArray'], + operators: ['equality', 'distinct', 'comparison', 'listArray'] }, { name: 'UUIDListFilter', tsType: 'string[]', - operators: ['equality', 'distinct', 'comparison', 'listArray'], - }, + operators: ['equality', 'distinct', 'comparison', 'listArray'] + } ]; /** @@ -542,7 +544,7 @@ function buildEntityProperties(table: CleanTable): InterfaceProperty[] { properties.push({ name: field.name, type: isNullable ? `${tsType} | null` : tsType, - optional: isNullable, + optional: isNullable }); } @@ -582,13 +584,13 @@ function generateRelationHelperTypes(): t.Statement[] { const connectionResultProps: t.TSPropertySignature[] = [ createPropertySignature('nodes', 'T[]', false), createPropertySignature('totalCount', 'number', false), - createPropertySignature('pageInfo', 'PageInfo', false), + createPropertySignature('pageInfo', 'PageInfo', false) ]; const connectionResultBody = t.tsInterfaceBody(connectionResultProps); const connectionResultDecl = t.tsInterfaceDeclaration( t.identifier('ConnectionResult'), t.tsTypeParameterDeclaration([ - t.tsTypeParameter(null, null, 'T'), + t.tsTypeParameter(null, null, 'T') ]), null, connectionResultBody @@ -601,7 +603,7 @@ function generateRelationHelperTypes(): t.Statement[] { { name: 'hasNextPage', type: 'boolean', optional: false }, { name: 'hasPreviousPage', type: 'boolean', optional: false }, { name: 'startCursor', type: 'string | null', optional: true }, - { name: 'endCursor', type: 'string | null', optional: true }, + { name: 'endCursor', type: 'string | null', optional: true } ]) ); @@ -663,7 +665,7 @@ function buildEntityRelationProperties( properties.push({ name: relation.fieldName, type: `${relatedTypeName} | null`, - optional: true, + optional: true }); } @@ -676,7 +678,7 @@ function buildEntityRelationProperties( properties.push({ name: relation.fieldName, type: `${relatedTypeName} | null`, - optional: true, + optional: true }); } @@ -689,7 +691,7 @@ function buildEntityRelationProperties( properties.push({ name: relation.fieldName, type: `ConnectionResult<${relatedTypeName}>`, - optional: true, + optional: true }); } @@ -702,7 +704,7 @@ function buildEntityRelationProperties( properties.push({ name: relation.fieldName, type: `ConnectionResult<${relatedTypeName}>`, - optional: true, + optional: true }); } @@ -803,8 +805,8 @@ function buildSelectTypeLiteral( ); selectProp.optional = true; return selectProp; - })(), - ]), + })() + ]) ]) ) ); @@ -869,8 +871,8 @@ function buildSelectTypeLiteral( ); p.optional = true; return p; - })(), - ]), + })() + ]) ]) ) ); @@ -932,8 +934,8 @@ function buildSelectTypeLiteral( ); p.optional = true; return p; - })(), - ]), + })() + ]) ]) ) ); @@ -964,8 +966,8 @@ function buildSelectTypeLiteral( ); selectProp.optional = true; return selectProp; - })(), - ]), + })() + ]) ]) ) ); @@ -1077,7 +1079,7 @@ function buildTableConditionProperties(table: CleanTable): InterfaceProperty[] { properties.push({ name: field.name, type: `${tsType} | null`, - optional: true, + optional: true }); } @@ -1214,7 +1216,7 @@ function buildCreateInputInterface(table: CleanTable): t.ExportNamedDeclaration t.tsPropertySignature( t.identifier(singularName), t.tsTypeAnnotation(nestedObjectType) - ), + ) ]; const body = t.tsInterfaceBody(mainProps); @@ -1249,7 +1251,7 @@ function buildPatchProperties(table: CleanTable): InterfaceProperty[] { properties.push({ name: field.name, type: `${tsType} | null`, - optional: true, + optional: true }); } @@ -1264,6 +1266,11 @@ 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)); @@ -1276,8 +1283,8 @@ function generateCrudInputTypes(table: CleanTable): t.Statement[] { statements.push( createExportedInterface(`Update${typeName}Input`, [ { name: 'clientMutationId', type: 'string', optional: true }, - { name: 'id', type: 'string', optional: false }, - { name: 'patch', type: patchName, optional: false }, + { name: pkFieldName, type: pkFieldTsType, optional: false }, + { name: 'patch', type: patchName, optional: false } ]) ); @@ -1285,7 +1292,7 @@ function generateCrudInputTypes(table: CleanTable): t.Statement[] { statements.push( createExportedInterface(`Delete${typeName}Input`, [ { name: 'clientMutationId', type: 'string', optional: true }, - { name: 'id', type: 'string', optional: false }, + { name: pkFieldName, type: pkFieldTsType, optional: false } ]) ); @@ -1456,10 +1463,7 @@ export function collectPayloadTypeNames( for (const op of operations) { const baseName = getTypeBaseName(op.returnType); - if ( - baseName && - (baseName.endsWith('Payload') || !baseName.endsWith('Connection')) - ) { + if (baseName) { payloadTypes.add(baseName); } } @@ -1494,7 +1498,7 @@ function generatePayloadTypes( 'BigFloat', 'Cursor', 'Query', - 'Mutation', + 'Mutation' ]); // Process all types - no artificial limit @@ -1524,7 +1528,7 @@ function generatePayloadTypes( interfaceProps.push({ name: field.name, type: isNullable ? `${tsType} | null` : tsType, - optional: isNullable, + optional: isNullable }); // Follow nested OBJECT types @@ -1563,8 +1567,8 @@ function generatePayloadTypes( ); p.optional = true; return p; - })(), - ]), + })() + ]) ]); } else { propType = t.tsBooleanKeyword(); @@ -1669,6 +1673,6 @@ export function generateInputTypesFile( return { fileName: 'input-types.ts', - content: header + '\n' + code, + content: header + '\n' + code }; } diff --git a/graphql/codegen/src/core/codegen/orm/model-generator.ts b/graphql/codegen/src/core/codegen/orm/model-generator.ts index 0498688b4..5b05c3e41 100644 --- a/graphql/codegen/src/core/codegen/orm/model-generator.ts +++ b/graphql/codegen/src/core/codegen/orm/model-generator.ts @@ -3,15 +3,19 @@ * * Generates per-table model classes with findMany, findFirst, create, update, delete methods. */ -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, + getDefaultSelectFieldName, getFilterTypeName, - lcFirst, getGeneratedFileHeader, + getOrderByTypeName, + getPrimaryKeyInfo, + getTableNames, + hasValidPrimaryKey, + lcFirst } from '../utils'; export interface GeneratedModelFile { @@ -45,10 +49,10 @@ function buildMethodBody( 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('variables'), t.identifier('variables'), false, true) ]), t.callExpression(t.identifier(builderFn), args) - ), + ) ]); const returnStmt = t.returnStatement( @@ -59,8 +63,8 @@ function buildMethodBody( 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('variables'), t.identifier('variables'), false, true) + ]) ]) ); @@ -80,16 +84,26 @@ function createClassMethod( return method; } -function createConstTypeParam(constraintTypeName: string): t.TSTypeParameterDeclaration { +function createConstTypeParam( + constraintTypeName: string, + defaultType?: t.TSType +): t.TSTypeParameterDeclaration { const param = t.tsTypeParameter( t.tsTypeReference(t.identifier(constraintTypeName)), - null, + 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)); +} + export function generateModelFile( table: CleanTable, _useSharedTypes: boolean @@ -109,6 +123,12 @@ export function generateModelFile( const deleteInputTypeName = `Delete${typeName}Input`; const patchTypeName = `${typeName}Patch`; + const pkFields = getPrimaryKeyInfo(table); + const pkField = pkFields[0]; + const pkFieldTsType = tsTypeFromPrimitive(pkField.tsType); + const defaultSelectIdent = t.identifier('defaultSelect'); + const defaultSelectFieldName = getDefaultSelectFieldName(table); + const pluralQueryName = table.query?.all ?? pluralName; const createMutationName = table.query?.create ?? `create${typeName}`; const updateMutationName = table.query?.update; @@ -118,18 +138,32 @@ export function generateModelFile( statements.push(createImportDeclaration('../client', ['OrmClient'])); statements.push(createImportDeclaration('../query-builder', [ - 'QueryBuilder', 'buildFindManyDocument', 'buildFindFirstDocument', - 'buildCreateDocument', 'buildUpdateDocument', 'buildDeleteDocument', + 'QueryBuilder', 'buildFindManyDocument', 'buildFindFirstDocument', 'buildFindOneDocument', + 'buildCreateDocument', 'buildUpdateByPkDocument', 'buildDeleteByPkDocument' ])); statements.push(createImportDeclaration('../select-types', [ 'ConnectionResult', 'FindManyArgs', 'FindFirstArgs', 'CreateArgs', - 'UpdateArgs', 'DeleteArgs', 'InferSelectResult', 'DeepExact', + 'UpdateArgs', 'DeleteArgs', 'InferSelectResult', 'DeepExact' ], true)); statements.push(createImportDeclaration('../input-types', [ typeName, relationTypeName, selectTypeName, whereTypeName, orderByTypeName, - createInputTypeName, updateInputTypeName, patchTypeName, + createInputTypeName, updateInputTypeName, patchTypeName ], true)); + // Default select (ensures valid GraphQL selection + sound TS return types) + statements.push( + t.variableDeclaration('const', [ + t.variableDeclarator( + defaultSelectIdent, + asConst( + t.objectExpression([ + t.objectProperty(t.identifier(defaultSelectFieldName), t.booleanLiteral(true)) + ]) + ) + ) + ]) + ); + const classBody: t.ClassBody['body'] = []; // Constructor @@ -147,10 +181,10 @@ export function generateModelFile( 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(selectTypeName)) ])), t.tsTypeReference(t.identifier(whereTypeName)), - t.tsTypeReference(t.identifier(orderByTypeName)), + t.tsTypeReference(t.identifier(orderByTypeName)) ])) ); const findManyReturnType = t.tsTypeAnnotation( @@ -160,17 +194,22 @@ export function generateModelFile( t.tsTypeReference(t.identifier('ConnectionResult'), t.tsTypeParameterInstantiation([ t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([ t.tsTypeReference(t.identifier(relationTypeName)), - t.tsTypeReference(t.identifier('S')), - ])), + t.tsTypeReference(t.identifier('S')) + ])) ])) - )), - ]), + )) + ]) ])) ); + const findManySelectExpr = t.logicalExpression( + '??', + t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), + defaultSelectIdent + ); const findManyArgs = [ t.stringLiteral(typeName), t.stringLiteral(pluralQueryName), - t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), + findManySelectExpr, t.objectExpression([ t.objectProperty(t.identifier('where'), t.optionalMemberExpression(t.identifier('args'), t.identifier('where'), false, true)), t.objectProperty(t.identifier('orderBy'), t.tsAsExpression( @@ -181,12 +220,12 @@ export function generateModelFile( 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.objectProperty(t.identifier('offset'), t.optionalMemberExpression(t.identifier('args'), t.identifier('offset'), false, true)) ]), t.stringLiteral(whereTypeName), - t.stringLiteral(orderByTypeName), + t.stringLiteral(orderByTypeName) ]; - classBody.push(createClassMethod('findMany', createConstTypeParam(selectTypeName), [findManyParam], findManyReturnType, + classBody.push(createClassMethod('findMany', createConstTypeParam(selectTypeName, t.tsTypeQuery(defaultSelectIdent)), [findManyParam], findManyReturnType, buildMethodBody('buildFindManyDocument', findManyArgs, 'query', typeName, pluralQueryName))); // findFirst method @@ -196,9 +235,9 @@ export function generateModelFile( 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(selectTypeName)) ])), - t.tsTypeReference(t.identifier(whereTypeName)), + t.tsTypeReference(t.identifier(whereTypeName)) ])) ); const findFirstReturnType = t.tsTypeAnnotation( @@ -209,35 +248,103 @@ export function generateModelFile( 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')), + t.tsTypeReference(t.identifier('S')) ]))) - )), + )) ]) - )), - ]), + )) + ]) ])) ); + const findFirstSelectExpr = t.logicalExpression( + '??', + t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), + defaultSelectIdent + ); const findFirstArgs = [ t.stringLiteral(typeName), t.stringLiteral(pluralQueryName), - t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), + findFirstSelectExpr, t.objectExpression([ - t.objectProperty(t.identifier('where'), t.optionalMemberExpression(t.identifier('args'), t.identifier('where'), false, true)), + t.objectProperty(t.identifier('where'), t.optionalMemberExpression(t.identifier('args'), t.identifier('where'), false, true)) ]), - t.stringLiteral(whereTypeName), + t.stringLiteral(whereTypeName) ]; - classBody.push(createClassMethod('findFirst', createConstTypeParam(selectTypeName), [findFirstParam], findFirstReturnType, + classBody.push(createClassMethod('findFirst', createConstTypeParam(selectTypeName, t.tsTypeQuery(defaultSelectIdent)), [findFirstParam], findFirstReturnType, buildMethodBody('buildFindFirstDocument', findFirstArgs, 'query', typeName, pluralQueryName))); + // findOne method (only if table has valid PK and singular query) + const singleQueryName = table.query?.one; + if (singleQueryName && hasValidPrimaryKey(table)) { + const pkGqlType = pkField.gqlType.replace(/!/g, '') + '!'; + + const findOneParam = t.identifier('args'); + findOneParam.typeAnnotation = t.tsTypeAnnotation( + t.tsTypeLiteral([ + (() => { + const prop = t.tsPropertySignature( + t.identifier(pkField.name), + t.tsTypeAnnotation(pkFieldTsType) + ); + prop.optional = false; + return prop; + })(), + (() => { + 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; + })() + ]) + ); + const findOneReturnType = 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)), + t.tsTypeReference(t.identifier('S')) + ])), + t.tsNullKeyword() + ]) + )) + ]) + ])) + ); + const findOneSelectExpr = t.logicalExpression( + '??', + t.memberExpression(t.identifier('args'), t.identifier('select')), + defaultSelectIdent + ); + const findOneArgs = [ + t.stringLiteral(typeName), + t.stringLiteral(singleQueryName), + t.memberExpression(t.identifier('args'), t.identifier(pkField.name)), + findOneSelectExpr, + t.stringLiteral(pkField.name), + t.stringLiteral(pkGqlType) + ]; + classBody.push(createClassMethod('findOne', createConstTypeParam(selectTypeName, t.tsTypeQuery(defaultSelectIdent)), [findOneParam], findOneReturnType, + buildMethodBody('buildFindOneDocument', findOneArgs, 'query', typeName, singleQueryName))); + } + // 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.tsTypeReference(t.identifier(selectTypeName)) ])), - t.tsIndexedAccessType(t.tsTypeReference(t.identifier(createInputTypeName)), t.tsLiteralType(t.stringLiteral(singularName))), + t.tsIndexedAccessType(t.tsTypeReference(t.identifier(createInputTypeName)), t.tsLiteralType(t.stringLiteral(singularName))) ])) ); const createReturnType = t.tsTypeAnnotation( @@ -248,23 +355,28 @@ export function generateModelFile( 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.tsTypeReference(t.identifier('S')) ])) - )), + )) ]) - )), - ]), + )) + ]) ])) ); + const createSelectExpr = t.logicalExpression( + '??', + t.memberExpression(t.identifier('args'), t.identifier('select')), + defaultSelectIdent + ); const createArgs = [ t.stringLiteral(typeName), t.stringLiteral(createMutationName), t.stringLiteral(entityLower), - t.memberExpression(t.identifier('args'), t.identifier('select')), + createSelectExpr, t.memberExpression(t.identifier('args'), t.identifier('data')), - t.stringLiteral(createInputTypeName), + t.stringLiteral(createInputTypeName) ]; - classBody.push(createClassMethod('create', createConstTypeParam(selectTypeName), [createParam], createReturnType, + classBody.push(createClassMethod('create', createConstTypeParam(selectTypeName, t.tsTypeQuery(defaultSelectIdent)), [createParam], createReturnType, buildMethodBody('buildCreateDocument', createArgs, 'mutation', typeName, createMutationName))); // update method (if available) @@ -274,10 +386,16 @@ export function generateModelFile( 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.tsTypeReference(t.identifier(selectTypeName)) ])), - t.tsTypeLiteral([t.tsPropertySignature(t.identifier('id'), t.tsTypeAnnotation(t.tsStringKeyword()))]), - t.tsTypeReference(t.identifier(patchTypeName)), + t.tsTypeLiteral([ + (() => { + const prop = t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkFieldTsType)); + prop.optional = false; + return prop; + })() + ]), + t.tsTypeReference(t.identifier(patchTypeName)) ])) ); const updateReturnType = t.tsTypeAnnotation( @@ -288,33 +406,52 @@ export function generateModelFile( 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.tsTypeReference(t.identifier('S')) ])) - )), + )) ]) - )), - ]), + )) + ]) ])) ); + const updateSelectExpr = t.logicalExpression( + '??', + t.memberExpression(t.identifier('args'), t.identifier('select')), + defaultSelectIdent + ); const updateArgs = [ 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')), + updateSelectExpr, + 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) ]; - classBody.push(createClassMethod('update', createConstTypeParam(selectTypeName), [updateParam], updateReturnType, - buildMethodBody('buildUpdateDocument', updateArgs, 'mutation', typeName, updateMutationName))); + classBody.push(createClassMethod('update', createConstTypeParam(selectTypeName, t.tsTypeQuery(defaultSelectIdent)), [updateParam], updateReturnType, + buildMethodBody('buildUpdateByPkDocument', updateArgs, 'mutation', typeName, updateMutationName))); } - // delete method (if available) + // delete method (if available) - supports optional select for returning entity fields 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()))]), + t.tsTypeLiteral([ + (() => { + const prop = t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkFieldTsType)); + prop.optional = false; + return prop; + })() + ]), + t.tsTypeReference(t.identifier('DeepExact'), t.tsTypeParameterInstantiation([ + t.tsTypeReference(t.identifier('S')), + t.tsTypeReference(t.identifier(selectTypeName)) + ])) ])) ); const deleteReturnType = t.tsTypeAnnotation( @@ -323,22 +460,35 @@ export function generateModelFile( t.tsPropertySignature(t.identifier(deleteMutationName), t.tsTypeAnnotation( t.tsTypeLiteral([ t.tsPropertySignature(t.identifier(entityLower), t.tsTypeAnnotation( - t.tsTypeLiteral([t.tsPropertySignature(t.identifier('id'), t.tsTypeAnnotation(t.tsStringKeyword()))]) - )), + t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([ + t.tsTypeReference(t.identifier(relationTypeName)), + t.tsTypeReference(t.identifier('S')) + ])) + )) ]) - )), - ]), + )) + ]) ])) ); + const deleteSelectExpr = t.logicalExpression( + '??', + t.memberExpression(t.identifier('args'), t.identifier('select')), + defaultSelectIdent + ); const deleteArgs = [ 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), + deleteSelectExpr ]; - classBody.push(createClassMethod('delete', null, [deleteParam], deleteReturnType, - buildMethodBody('buildDeleteDocument', deleteArgs, 'mutation', typeName, deleteMutationName))); + classBody.push(createClassMethod('delete', createConstTypeParam(selectTypeName, t.tsTypeQuery(defaultSelectIdent)), [deleteParam], deleteReturnType, + buildMethodBody('buildDeleteByPkDocument', deleteArgs, 'mutation', typeName, deleteMutationName))); } const classDecl = t.classDeclaration(t.identifier(modelName), null, t.classBody(classBody)); diff --git a/graphql/codegen/src/core/codegen/queries.ts b/graphql/codegen/src/core/codegen/queries.ts index 55852c339..5e6d7285b 100644 --- a/graphql/codegen/src/core/codegen/queries.ts +++ b/graphql/codegen/src/core/codegen/queries.ts @@ -1,39 +1,28 @@ /** - * Query hook generators using Babel AST-based code generation + * Query hook generators - delegates to ORM model methods * * 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 { - buildListQueryAST, - buildSingleQueryAST, - printGraphQL, -} from './gql-ast'; -import { - getTableNames, - getListQueryHookName, - getSingleQueryHookName, - getListQueryFileName, - getSingleQueryFileName, getAllRowsQueryName, - getSingleRowQueryName, + getDefaultSelectFieldName, getFilterTypeName, - getConditionTypeName, + getGeneratedFileHeader, + getListQueryFileName, + getListQueryHookName, getOrderByTypeName, - getScalarFields, - getScalarFilterType, getPrimaryKeyInfo, + getSingleQueryFileName, + getSingleQueryHookName, + getSingleRowQueryName, + getTableNames, hasValidPrimaryKey, - fieldTypeToTs, - toScreamingSnake, - ucFirst, lcFirst, - getGeneratedFileHeader, + ucFirst } from './utils'; export interface GeneratedQueryFile { @@ -47,55 +36,6 @@ 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 = {} @@ -103,742 +43,194 @@ export function generateListQueryHook( const { reactQueryEnabled = true, useCentralizedKeys = true, - hasRelationships = false, + 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 defaultFieldName = getDefaultSelectFieldName(table); - 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); - } - } + const lines: string[] = []; + // Imports if (reactQueryEnabled) { - const reactQueryImport = t.importDeclaration( - [t.importSpecifier(t.identifier('useQuery'), t.identifier('useQuery'))], - t.stringLiteral('@tanstack/react-query') - ); - 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') - ); - reactQueryTypeImport.importKind = 'type'; - statements.push(reactQueryTypeImport); + lines.push(`import { useQuery } from '@tanstack/react-query';`); + lines.push(`import type { UseQueryOptions, QueryClient } from '@tanstack/react-query';`); } - - 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') - ); - 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') - ); - typesImport.importKind = 'type'; - statements.push(typesImport); + lines.push(`import { getClient } from '../client';`); if (useCentralizedKeys) { - const queryKeyImport = t.importDeclaration( - [t.importSpecifier(t.identifier(keysName), t.identifier(keysName))], - t.stringLiteral('../query-keys') - ); - statements.push(queryKeyImport); + lines.push(`import { ${keysName} } from '../query-keys';`); 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 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; + lines.push(`import type { ${scopeTypeName} } from '../query-keys';`); } - ); - - // 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) - ); - 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(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) - ), - ]); - const resultInterface = t.tsInterfaceDeclaration( - t.identifier(`${ucFirst(pluralName)}QueryResult`), - null, - null, - resultInterfaceBody - ); - statements.push(t.exportNamedDeclaration(resultInterface)); - + lines.push(`import type {`); + lines.push(` ${selectTypeName},`); + lines.push(` ${relationTypeName},`); + lines.push(` ${filterTypeName},`); + lines.push(` ${orderByTypeName},`); + lines.push(`} from '../../orm/input-types';`); + lines.push(`import type {`); + lines.push(` FindManyArgs,`); + lines.push(` DeepExact,`); + lines.push(` InferSelectResult,`); + lines.push(` ConnectionResult,`); + lines.push(`} from '../../orm/select-types';`); + lines.push(''); + + // Re-export types for backwards compat + lines.push(`export type { ${selectTypeName}, ${relationTypeName}, ${filterTypeName}, ${orderByTypeName} } from '../../orm/input-types';`); + lines.push(''); + + lines.push(`const defaultSelect = { ${defaultFieldName}: true } as const;`); + lines.push(''); + + // 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, [ - 'Query key factory - re-exported from query-keys.ts', - ]); - statements.push(queryKeyExport); + lines.push(`/** Query key factory - re-exported from query-keys.ts */`); + lines.push(`export const ${queryName}QueryKey = ${keysName}.list;`); } else { - const queryKeyArrow = t.arrowFunctionExpression( - [ - typedParam( - 'variables', - t.tsTypeReference( - t.identifier(`${ucFirst(pluralName)}QueryVariables`) - ), - true - ), - ], - t.tsAsExpression( - 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(queryKeyConst)); + lines.push(`export const ${queryName}QueryKey = (variables?: FindManyArgs) => ['${typeName.toLowerCase()}', 'list', variables] as const;`); } + lines.push(''); + // Hook if (reactQueryEnabled) { - const hookBodyStatements: t.Statement[] = []; + const docLines = [ + `/**`, + ` * Query hook for fetching ${typeName} list`, + ` *`, + ` * @example`, + ` * \`\`\`tsx`, + ` * const { data, isLoading } = ${hookName}({`, + ` * select: { id: true, name: true },`, + ` * first: 10,`, + ` * where: { name: { equalTo: "example" } },`, + ` * orderBy: ['CREATED_AT_DESC'],`, + ` * });`, + ` * \`\`\`` + ]; 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')), - ]), - ]) - ) - ); + 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(` * \`\`\``); } + docLines.push(` */`); + lines.push(...docLines); - const hookParams: t.Identifier[] = [ - typedParam( - 'variables', - t.tsTypeReference(t.identifier(`${ucFirst(pluralName)}QueryVariables`)), - true - ), - ]; - let optionsTypeStr: string; + let optionsType: string; if (hasRelationships && useCentralizedKeys) { - optionsTypeStr = `Omit, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }`; + optionsType = `Omit> }, Error>, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }`; } else { - optionsTypeStr = `Omit, 'queryKey' | 'queryFn'>`; + optionsType = `Omit> }, Error>, '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) - ); - const hookExport = t.exportNamedDeclaration(hookFunc); - const docLines = [ - `Query hook for fetching ${typeName} list`, - '', - '@example', - '```tsx', - `const { data, isLoading } = ${hookName}({`, - ' first: 10,', - ' filter: { name: { equalTo: "example" } },', - " orderBy: ['CREATED_AT_DESC'],", - '});', - '```', - ]; + lines.push(`export function ${hookName}(`); + lines.push(` args?: FindManyArgs, ${filterTypeName}, ${orderByTypeName}>,`); + lines.push(` options?: ${optionsType}`); + lines.push(`) {`); + if (hasRelationships && useCentralizedKeys) { - 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('```'); + lines.push(` const { scope, ...queryOptions } = options ?? {};`); + lines.push(` return useQuery({`); + lines.push(` queryKey: ${keysName}.list(args, scope),`); + lines.push(` queryFn: () => getClient().${singularName}.findMany(args).unwrap(),`); + lines.push(` ...queryOptions,`); + lines.push(` });`); + } else if (useCentralizedKeys) { + lines.push(` return useQuery({`); + lines.push(` queryKey: ${keysName}.list(args),`); + lines.push(` queryFn: () => getClient().${singularName}.findMany(args).unwrap(),`); + lines.push(` ...options,`); + lines.push(` });`); + } else { + lines.push(` return useQuery({`); + lines.push(` queryKey: ${queryName}QueryKey(args),`); + lines.push(` queryFn: () => getClient().${singularName}.findMany(args).unwrap(),`); + lines.push(` ...options,`); + lines.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); + lines.push(`}`); + lines.push(''); + } + // Fetch function (non-hook) + lines.push(`/**`); + lines.push(` * Fetch ${typeName} list without React hooks`); + lines.push(` *`); + lines.push(` * @example`); + lines.push(` * \`\`\`ts`); + lines.push(` * const data = await fetch${ucFirst(pluralName)}Query({ first: 10, select: { id: true } });`); + lines.push(` * \`\`\``); + lines.push(` */`); + lines.push(`export async function fetch${ucFirst(pluralName)}Query(`); + lines.push(` args?: FindManyArgs, ${filterTypeName}, ${orderByTypeName}>,`); + lines.push(`) {`); + lines.push(` return getClient().${singularName}.findMany(args).unwrap();`); + lines.push(`}`); + lines.push(''); + + // Prefetch function if (reactQueryEnabled) { - const prefetchParams: t.Identifier[] = [ - typedParam( - 'queryClient', - t.tsTypeReference(t.identifier('QueryClient')) - ), - typedParam( - 'variables', - t.tsTypeReference(t.identifier(`${ucFirst(pluralName)}QueryVariables`)), - true - ), - ]; + lines.push(`/**`); + lines.push(` * Prefetch ${typeName} list for SSR or cache warming`); + lines.push(` *`); + lines.push(` * @example`); + lines.push(` * \`\`\`ts`); + lines.push(` * await prefetch${ucFirst(pluralName)}Query(queryClient, { first: 10 });`); + lines.push(` * \`\`\``); + lines.push(` */`); + lines.push(`export async function prefetch${ucFirst(pluralName)}Query(`); + lines.push(` queryClient: QueryClient,`); + lines.push(` args?: FindManyArgs, ${filterTypeName}, ${orderByTypeName}>,`); if (hasRelationships && useCentralizedKeys) { - prefetchParams.push( - typedParam( - 'scope', - t.tsTypeReference(t.identifier(scopeTypeName)), - true - ) - ); + lines.push(` scope?: ${scopeTypeName},`); } - prefetchParams.push( - typedParam( - 'options', - t.tsTypeReference(t.identifier('ExecuteOptions')), - true - ) - ); + lines.push(`): Promise {`); - let prefetchQueryKeyExpr: t.Expression; if (hasRelationships && useCentralizedKeys) { - prefetchQueryKeyExpr = t.callExpression( - t.memberExpression(t.identifier(keysName), t.identifier('list')), - [t.identifier('variables'), t.identifier('scope')] - ); + lines.push(` await queryClient.prefetchQuery({`); + lines.push(` queryKey: ${keysName}.list(args, scope),`); + lines.push(` queryFn: () => getClient().${singularName}.findMany(args).unwrap(),`); + lines.push(` });`); } else if (useCentralizedKeys) { - prefetchQueryKeyExpr = t.callExpression( - t.memberExpression(t.identifier(keysName), t.identifier('list')), - [t.identifier('variables')] - ); + lines.push(` await queryClient.prefetchQuery({`); + lines.push(` queryKey: ${keysName}.list(args),`); + lines.push(` queryFn: () => getClient().${singularName}.findMany(args).unwrap(),`); + lines.push(` });`); } else { - prefetchQueryKeyExpr = t.callExpression( - t.identifier(`${queryName}QueryKey`), - [t.identifier('variables')] - ); + lines.push(` await queryClient.prefetchQuery({`); + lines.push(` queryKey: ${queryName}QueryKey(args),`); + lines.push(` queryFn: () => getClient().${singularName}.findMany(args).unwrap(),`); + lines.push(` });`); } - 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`)), - ] - ) - ) - ), - ]), - ] - ) - ) - ), - ]); - - const prefetchFunc = t.functionDeclaration( - t.identifier(`prefetch${ucFirst(pluralName)}Query`), - prefetchParams, - prefetchFuncBody - ); - prefetchFunc.async = true; - prefetchFunc.returnType = t.tsTypeAnnotation( - t.tsTypeReference( - t.identifier('Promise'), - t.tsTypeParameterInstantiation([t.tsVoidKeyword()]) - ) - ); - const prefetchExport = t.exportNamedDeclaration(prefetchFunc); - addJSDocComment(prefetchExport, [ - `Prefetch ${typeName} list for SSR or cache warming`, - '', - '@example', - '```ts', - `await prefetch${ucFirst(pluralName)}Query(queryClient, { first: 10 });`, - '```', - ]); - statements.push(prefetchExport); + lines.push(`}`); } - const code = generateCode(statements); const headerText = reactQueryEnabled ? `List query hook for ${typeName}` : `List query functions for ${typeName}`; - const content = getGeneratedFileHeader(headerText) + '\n\n' + code; + const content = getGeneratedFileHeader(headerText) + '\n\n' + lines.join('\n') + '\n'; return { fileName: getListQueryFileName(table), - content, + content }; } @@ -846,7 +238,6 @@ export function generateSingleQueryHook( table: CleanTable, options: QueryGeneratorOptions = {} ): GeneratedQueryFile | null { - // Skip tables with composite keys - they are handled as custom queries if (!hasValidPrimaryKey(table)) { return null; } @@ -854,536 +245,190 @@ export function generateSingleQueryHook( const { reactQueryEnabled = true, useCentralizedKeys = true, - hasRelationships = false, + hasRelationships = false } = options; const { typeName, singularName } = getTableNames(table); const hookName = getSingleQueryHookName(table); 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 defaultFieldName = getDefaultSelectFieldName(table); - const queryAST = buildSingleQueryAST({ table }); - const queryDocument = printGraphQL(queryAST); - - const statements: t.Statement[] = []; + const lines: string[] = []; + // Imports if (reactQueryEnabled) { - const reactQueryImport = t.importDeclaration( - [t.importSpecifier(t.identifier('useQuery'), t.identifier('useQuery'))], - t.stringLiteral('@tanstack/react-query') - ); - 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') - ); - reactQueryTypeImport.importKind = 'type'; - statements.push(reactQueryTypeImport); + lines.push(`import { useQuery } from '@tanstack/react-query';`); + lines.push(`import type { UseQueryOptions, QueryClient } from '@tanstack/react-query';`); } - - 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') - ); - clientTypeImport.importKind = 'type'; - statements.push(clientTypeImport); - - const typesImport = t.importDeclaration( - [t.importSpecifier(t.identifier(typeName), t.identifier(typeName))], - t.stringLiteral('../types') - ); - typesImport.importKind = 'type'; - statements.push(typesImport); + lines.push(`import { getClient } from '../client';`); if (useCentralizedKeys) { - const queryKeyImport = t.importDeclaration( - [t.importSpecifier(t.identifier(keysName), t.identifier(keysName))], - t.stringLiteral('../query-keys') - ); - statements.push(queryKeyImport); + lines.push(`import { ${keysName} } from '../query-keys';`); if (hasRelationships) { - const scopeTypeImport = t.importDeclaration( - [ - t.importSpecifier( - t.identifier(scopeTypeName), - t.identifier(scopeTypeName) - ), - ], - t.stringLiteral('../query-keys') - ); - scopeTypeImport.importKind = 'type'; - statements.push(scopeTypeImport); + lines.push(`import type { ${scopeTypeName} } from '../query-keys';`); } } - 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 pkTypeAnnotation = - pkTsType === 'string' - ? t.tsStringKeyword() - : pkTsType === 'number' - ? t.tsNumberKeyword() - : t.tsTypeReference(t.identifier(pkTsType)); + lines.push(`import type {`); + lines.push(` ${selectTypeName},`); + lines.push(` ${relationTypeName},`); + lines.push(`} from '../../orm/input-types';`); + lines.push(`import type {`); + lines.push(` DeepExact,`); + lines.push(` InferSelectResult,`); + lines.push(`} from '../../orm/select-types';`); + lines.push(''); - const variablesInterfaceBody = t.tsInterfaceBody([ - t.tsPropertySignature( - t.identifier(pkName), - t.tsTypeAnnotation(pkTypeAnnotation) - ), - ]); - const variablesInterface = t.tsInterfaceDeclaration( - t.identifier(`${ucFirst(singularName)}QueryVariables`), - null, - null, - variablesInterfaceBody - ); - statements.push(t.exportNamedDeclaration(variablesInterface)); + // Re-export types + lines.push(`export type { ${selectTypeName}, ${relationTypeName} } from '../../orm/input-types';`); + lines.push(''); - const resultInterfaceBody = t.tsInterfaceBody([ - t.tsPropertySignature( - t.identifier(queryName), - t.tsTypeAnnotation( - t.tsUnionType([ - t.tsTypeReference(t.identifier(typeName)), - t.tsNullKeyword(), - ]) - ) - ), - ]); - const resultInterface = t.tsInterfaceDeclaration( - t.identifier(`${ucFirst(singularName)}QueryResult`), - null, - null, - resultInterfaceBody - ); - statements.push(t.exportNamedDeclaration(resultInterface)); + lines.push(`const defaultSelect = { ${defaultFieldName}: true } as const;`); + lines.push(''); + // 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, [ - 'Query key factory - re-exported from query-keys.ts', - ]); - statements.push(queryKeyExport); + lines.push(`/** Query key factory - re-exported from query-keys.ts */`); + lines.push(`export const ${queryName}QueryKey = ${keysName}.detail;`); } else { - const queryKeyArrow = t.arrowFunctionExpression( - [typedParam(pkName, pkTypeAnnotation)], - t.tsAsExpression( - t.arrayExpression([ - t.stringLiteral(typeName.toLowerCase()), - t.stringLiteral('detail'), - t.identifier(pkName), - ]), - t.tsTypeReference(t.identifier('const')) - ) - ); - const queryKeyConst = t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier(`${queryName}QueryKey`), - queryKeyArrow - ), - ]); - statements.push(t.exportNamedDeclaration(queryKeyConst)); + lines.push(`export const ${queryName}QueryKey = (id: ${pkFieldTsType}) => ['${typeName.toLowerCase()}', 'detail', id] as const;`); } + lines.push(''); + // Hook if (reactQueryEnabled) { - const hookBodyStatements: t.Statement[] = []; + const docLines = [ + `/**`, + ` * Query hook for fetching a single ${typeName}`, + ` *`, + ` * @example`, + ` * \`\`\`tsx`, + ` * const { data, isLoading } = ${hookName}({`, + ` * ${pkFieldName}: 'some-id',`, + ` * select: { id: true, name: true },`, + ` * });`, + ` * \`\`\`` + ]; 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')), - ]), - ]) - ) - ); + docLines.push(` *`); + docLines.push(` * @example With scope for hierarchical cache invalidation`); + docLines.push(` * \`\`\`tsx`); + docLines.push(` * const { data } = ${hookName}(`); + docLines.push(` * { ${pkFieldName}: 'some-id' },`); + docLines.push(` * { scope: { parentId: 'parent-id' } }`); + docLines.push(` * );`); + docLines.push(` * \`\`\``); } + docLines.push(` */`); + lines.push(...docLines); - const hookParams: t.Identifier[] = [ - typedParam( - 'variables', - t.tsTypeReference(t.identifier(`${ucFirst(singularName)}QueryVariables`)) - ), - ]; - let optionsTypeStr: string; + let optionsType: string; if (hasRelationships && useCentralizedKeys) { - optionsTypeStr = `Omit, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }`; + optionsType = `Omit | null }, Error>, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }`; } else { - optionsTypeStr = `Omit, 'queryKey' | 'queryFn'>`; + optionsType = `Omit | null }, Error>, '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) - ); - const hookExport = t.exportNamedDeclaration(hookFunc); - const docLines = [ - `Query hook for fetching a single ${typeName}`, - '', - '@example', - '```tsx', - `const { data, isLoading } = ${hookName}({ ${pkName}: 'some-id' });`, - '```', - ]; + lines.push(`export function ${hookName}(`); + lines.push(` args: { ${pkFieldName}: ${pkFieldTsType}; select?: DeepExact },`); + lines.push(` options?: ${optionsType}`); + lines.push(`) {`); + 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('```'); + lines.push(` const { scope, ...queryOptions } = options ?? {};`); + lines.push(` return useQuery({`); + lines.push(` queryKey: ${keysName}.detail(args.${pkFieldName}, scope),`); + lines.push(` queryFn: () => getClient().${singularName}.findOne(args).unwrap(),`); + lines.push(` ...queryOptions,`); + lines.push(` });`); + } else if (useCentralizedKeys) { + lines.push(` return useQuery({`); + lines.push(` queryKey: ${keysName}.detail(args.${pkFieldName}),`); + lines.push(` queryFn: () => getClient().${singularName}.findOne(args).unwrap(),`); + lines.push(` ...options,`); + lines.push(` });`); + } else { + lines.push(` return useQuery({`); + lines.push(` queryKey: ${queryName}QueryKey(args.${pkFieldName}),`); + lines.push(` queryFn: () => getClient().${singularName}.findOne(args).unwrap(),`); + lines.push(` ...options,`); + lines.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`)) - ), - 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(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); + lines.push(`}`); + lines.push(''); + } + // Fetch function + lines.push(`/**`); + lines.push(` * Fetch a single ${typeName} without React hooks`); + lines.push(` *`); + lines.push(` * @example`); + lines.push(` * \`\`\`ts`); + lines.push(` * const data = await fetch${ucFirst(singularName)}Query({ ${pkFieldName}: 'some-id', select: { id: true } });`); + lines.push(` * \`\`\``); + lines.push(` */`); + lines.push(`export async function fetch${ucFirst(singularName)}Query(`); + lines.push(` args: { ${pkFieldName}: ${pkFieldTsType}; select?: DeepExact },`); + lines.push(`) {`); + lines.push(` return getClient().${singularName}.findOne(args).unwrap();`); + lines.push(`}`); + lines.push(''); + + // Prefetch function if (reactQueryEnabled) { - const prefetchParams: t.Identifier[] = [ - typedParam( - 'queryClient', - t.tsTypeReference(t.identifier('QueryClient')) - ), - typedParam( - 'variables', - t.tsTypeReference(t.identifier(`${ucFirst(singularName)}QueryVariables`)) - ), - ]; + lines.push(`/**`); + lines.push(` * Prefetch a single ${typeName} for SSR or cache warming`); + lines.push(` *`); + lines.push(` * @example`); + lines.push(` * \`\`\`ts`); + lines.push(` * await prefetch${ucFirst(singularName)}Query(queryClient, { ${pkFieldName}: 'some-id' });`); + lines.push(` * \`\`\``); + lines.push(` */`); + lines.push(`export async function prefetch${ucFirst(singularName)}Query(`); + lines.push(` queryClient: QueryClient,`); + lines.push(` args: { ${pkFieldName}: ${pkFieldTsType}; select?: DeepExact },`); if (hasRelationships && useCentralizedKeys) { - prefetchParams.push( - typedParam( - 'scope', - t.tsTypeReference(t.identifier(scopeTypeName)), - true - ) - ); + lines.push(` scope?: ${scopeTypeName},`); } - prefetchParams.push( - typedParam( - 'options', - t.tsTypeReference(t.identifier('ExecuteOptions')), - true - ) - ); + lines.push(`): Promise {`); - 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'), - ] - ); + lines.push(` await queryClient.prefetchQuery({`); + lines.push(` queryKey: ${keysName}.detail(args.${pkFieldName}, scope),`); + lines.push(` queryFn: () => getClient().${singularName}.findOne(args).unwrap(),`); + lines.push(` });`); } else if (useCentralizedKeys) { - prefetchQueryKeyExpr = t.callExpression( - t.memberExpression(t.identifier(keysName), t.identifier('detail')), - [t.memberExpression(t.identifier('variables'), t.identifier(pkName))] - ); + lines.push(` await queryClient.prefetchQuery({`); + lines.push(` queryKey: ${keysName}.detail(args.${pkFieldName}),`); + lines.push(` queryFn: () => getClient().${singularName}.findOne(args).unwrap(),`); + lines.push(` });`); } else { - prefetchQueryKeyExpr = t.callExpression( - t.identifier(`${queryName}QueryKey`), - [t.memberExpression(t.identifier('variables'), t.identifier(pkName))] - ); + lines.push(` await queryClient.prefetchQuery({`); + lines.push(` queryKey: ${queryName}QueryKey(args.${pkFieldName}),`); + lines.push(` queryFn: () => getClient().${singularName}.findOne(args).unwrap(),`); + lines.push(` });`); } - 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`)), - ] - ) - ) - ), - ]), - ] - ) - ) - ), - ]); - - const prefetchFunc = t.functionDeclaration( - t.identifier(`prefetch${ucFirst(singularName)}Query`), - prefetchParams, - prefetchFuncBody - ); - prefetchFunc.async = true; - prefetchFunc.returnType = t.tsTypeAnnotation( - t.tsTypeReference( - t.identifier('Promise'), - t.tsTypeParameterInstantiation([t.tsVoidKeyword()]) - ) - ); - const prefetchExport = t.exportNamedDeclaration(prefetchFunc); - addJSDocComment(prefetchExport, [ - `Prefetch a single ${typeName} for SSR or cache warming`, - '', - '@example', - '```ts', - `await prefetch${ucFirst(singularName)}Query(queryClient, { ${pkName}: 'some-id' });`, - '```', - ]); - statements.push(prefetchExport); + lines.push(`}`); } - 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; + const content = getGeneratedFileHeader(headerText) + '\n\n' + lines.join('\n') + '\n'; return { fileName: getSingleQueryFileName(table), - content, + content }; } diff --git a/graphql/codegen/src/core/codegen/query-keys.ts b/graphql/codegen/src/core/codegen/query-keys.ts index 791d4eec6..b9c09c468 100644 --- a/graphql/codegen/src/core/codegen/query-keys.ts +++ b/graphql/codegen/src/core/codegen/query-keys.ts @@ -10,17 +10,17 @@ */ 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[]; @@ -558,7 +558,7 @@ function generateUnifiedStoreDeclaration( '', '// Invalidate specific user', 'queryClient.invalidateQueries({ queryKey: queryKeys.user.detail(userId) });', - '```', + '```' ]); return decl; @@ -714,6 +714,6 @@ ${description} return { fileName: 'query-keys.ts', - content, + content }; } diff --git a/graphql/codegen/src/core/codegen/scalars.ts b/graphql/codegen/src/core/codegen/scalars.ts index f659cb095..f13047967 100644 --- a/graphql/codegen/src/core/codegen/scalars.ts +++ b/graphql/codegen/src/core/codegen/scalars.ts @@ -40,7 +40,7 @@ export const SCALAR_TS_MAP: Record = { TsQuery: 'string', // File upload - Upload: 'File', + Upload: 'File' }; export const SCALAR_FILTER_MAP: Record = { @@ -59,7 +59,7 @@ export const SCALAR_FILTER_MAP: Record = { BitString: 'BitStringFilter', InternetAddress: 'InternetAddressFilter', FullText: 'FullTextFilter', - Interval: 'StringFilter', + Interval: 'StringFilter' }; export const SCALAR_NAMES = new Set(Object.keys(SCALAR_TS_MAP)); @@ -70,7 +70,7 @@ const LIST_FILTER_SCALARS = new Set(['String', 'Int', 'UUID']); /** All base filter type names - skip these in schema-types.ts to avoid duplicates */ export const BASE_FILTER_TYPE_NAMES = new Set([ ...new Set(Object.values(SCALAR_FILTER_MAP)), - ...Array.from(LIST_FILTER_SCALARS).map((s) => `${s}ListFilter`), + ...Array.from(LIST_FILTER_SCALARS).map((s) => `${s}ListFilter`) ]); export function scalarToTsType( 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..0e8e4b6a1 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 { @@ -49,7 +50,7 @@ const SKIP_TYPES = new Set([ '__InputValue', '__EnumValue', '__Directive', - ...BASE_FILTER_TYPE_NAMES, + ...BASE_FILTER_TYPE_NAMES ]); const SKIP_TYPE_PATTERNS: RegExp[] = []; @@ -390,6 +391,6 @@ export function generateSchemaTypesFile( fileName: 'schema-types.ts', content, generatedEnums: Array.from(enumResult.generatedTypes).sort(), - referencedTableTypes, + referencedTableTypes }; } 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..d17a770e3 --- /dev/null +++ b/graphql/codegen/src/core/codegen/select-helpers.ts @@ -0,0 +1,90 @@ +/** + * 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, TypeRegistry } 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 +): string { + if (typeRef.kind === 'NON_NULL' && typeRef.ofType) { + return wrapInferSelectResult(typeRef.ofType as CleanArgument['type'], payloadTypeName); + } + + if (typeRef.kind === 'LIST' && typeRef.ofType) { + return `${wrapInferSelectResult(typeRef.ofType as CleanArgument['type'], payloadTypeName)}[]`; + } + + return `InferSelectResult<${payloadTypeName}, S>`; +} + +/** + * Build a default select literal string for a given type. + * Finds an 'id' or 'nodeId' field, or falls back to first scalar field. + */ +export function buildDefaultSelectLiteral( + typeName: string, + typeRegistry: TypeRegistry, + depth: number = 0 +): string { + const resolved = typeRegistry.get(typeName); + const fields = resolved?.fields ?? []; + + if (depth > 3 || fields.length === 0) { + // Use first field if available, otherwise fallback to 'id' + return fields.length > 0 ? `{ ${fields[0].name}: true }` : `{ id: true }`; + } + + const idLike = fields.find((f) => f.name === 'id' || f.name === 'nodeId'); + if (idLike) return `{ ${idLike.name}: true }`; + + const scalarField = fields.find((f) => { + const baseName = getTypeBaseName(f.type); + if (!baseName) return false; + if (NON_SELECT_TYPES.has(baseName)) return true; + return typeRegistry.get(baseName)?.kind === 'ENUM'; + }); + if (scalarField) return `{ ${scalarField.name}: true }`; + + const first = fields[0]; + + const firstBase = getTypeBaseName(first.type); + if (!firstBase || NON_SELECT_TYPES.has(firstBase) || typeRegistry.get(firstBase)?.kind === 'ENUM') { + return `{ ${first.name}: true }`; + } + + const nested = buildDefaultSelectLiteral(firstBase, typeRegistry, depth + 1); + return `{ ${first.name}: { select: ${nested} } }`; +} diff --git a/graphql/codegen/src/core/codegen/shared/index.ts b/graphql/codegen/src/core/codegen/shared/index.ts index ccf6819fe..ccc31ead8 100644 --- a/graphql/codegen/src/core/codegen/shared/index.ts +++ b/graphql/codegen/src/core/codegen/shared/index.ts @@ -11,12 +11,13 @@ * 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'; /** @@ -64,14 +65,14 @@ export function generateSharedTypes(options: GenerateSharedOptions): GenerateSha if (customOperations && customOperations.typeRegistry) { const schemaTypesResult = generateSchemaTypesFile({ typeRegistry: customOperations.typeRegistry, - tableTypeNames, + tableTypeNames }); // Only include if there's meaningful content if (schemaTypesResult.content.split('\n').length > 10) { files.push({ path: 'schema-types.ts', - content: schemaTypesResult.content, + content: schemaTypesResult.content }); hasSchemaTypes = true; generatedEnumNames = schemaTypesResult.generatedEnums || []; @@ -82,21 +83,21 @@ export function generateSharedTypes(options: GenerateSharedOptions): GenerateSha files.push({ path: 'types.ts', content: generateTypesFile(tables, { - enumsFromSchemaTypes: generatedEnumNames, - }), + enumsFromSchemaTypes: generatedEnumNames + }) }); // 3. Generate barrel export (index.ts) const barrelContent = generateSharedBarrel(hasSchemaTypes); files.push({ path: 'index.ts', - content: barrelContent, + content: barrelContent }); return { files, generatedEnumNames, - hasSchemaTypes, + hasSchemaTypes }; } @@ -118,12 +119,12 @@ function generateSharedBarrel(hasSchemaTypes: boolean): string { if (statements.length > 0) { addJSDocComment(statements[0], [ 'Shared types - auto-generated, do not edit', - '@generated by @constructive-io/graphql-codegen', + '@generated by @constructive-io/graphql-codegen' ]); } 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/orm-client.ts b/graphql/codegen/src/core/codegen/templates/orm-client.ts index a71633d67..c6993a338 100644 --- a/graphql/codegen/src/core/codegen/templates/orm-client.ts +++ b/graphql/codegen/src/core/codegen/templates/orm-client.ts @@ -11,13 +11,13 @@ import type { GraphQLAdapter, GraphQLError, - QueryResult, + QueryResult } from '@constructive-io/graphql-types'; export type { GraphQLAdapter, GraphQLError, - QueryResult, + QueryResult } from '@constructive-io/graphql-types'; /** @@ -43,19 +43,19 @@ export class FetchAdapter implements GraphQLAdapter { headers: { 'Content-Type': 'application/json', Accept: 'application/json', - ...this.headers, + ...this.headers }, body: JSON.stringify({ query: document, - variables: variables ?? {}, - }), + variables: variables ?? {} + }) }); if (!response.ok) { return { ok: false, data: null, - errors: [{ message: `HTTP ${response.status}: ${response.statusText}` }], + errors: [{ message: `HTTP ${response.status}: ${response.statusText}` }] }; } @@ -68,14 +68,14 @@ export class FetchAdapter implements GraphQLAdapter { return { ok: false, data: null, - errors: json.errors, + errors: json.errors }; } return { ok: true, data: json.data as T, - errors: undefined, + errors: undefined }; } diff --git a/graphql/codegen/src/core/codegen/templates/query-builder.ts b/graphql/codegen/src/core/codegen/templates/query-builder.ts index 869e210e8..a678fbbd0 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, - FieldNode, - VariableDefinitionNode, EnumValueNode, + FieldNode, + VariableDefinitionNode } from 'graphql'; -import { OrmClient, QueryResult, GraphQLRequestError } from './client'; + +import { GraphQLRequestError,OrmClient, QueryResult } from './client'; export interface QueryBuilderConfig { client: OrmClient; @@ -133,7 +134,7 @@ export function buildSelections( nested.filter ? t.argument({ name: 'filter', value: buildValueAst(nested.filter) }) : null, - buildEnumListArg('orderBy', nested.orderBy), + buildEnumListArg('orderBy', nested.orderBy) ]); if (isConnection) { @@ -142,8 +143,8 @@ export function buildSelections( name: key, args, selectionSet: t.selectionSet({ - selections: buildConnectionSelections(nestedSelections), - }), + selections: buildConnectionSelections(nestedSelections) + }) }) ); } else { @@ -151,7 +152,7 @@ export function buildSelections( t.field({ name: key, args, - selectionSet: t.selectionSet({ selections: nestedSelections }), + selectionSet: t.selectionSet({ selections: nestedSelections }) }) ); } @@ -200,7 +201,7 @@ export function buildFindManyDocument( { varName: 'orderBy', typeName: '[' + orderByTypeName + '!]', - value: args.orderBy?.length ? args.orderBy : undefined, + value: args.orderBy?.length ? args.orderBy : undefined }, variableDefinitions, queryArgs, @@ -249,13 +250,13 @@ export function buildFindManyDocument( name: queryField, args: queryArgs.length ? queryArgs : undefined, selectionSet: t.selectionSet({ - selections: buildConnectionSelections(selections), - }), - }), - ], - }), - }), - ], + selections: buildConnectionSelections(selections) + }) + }) + ] + }) + }) + ] }); return { document: print(document), variables }; @@ -305,15 +306,15 @@ export function buildFindFirstDocument( selections: [ t.field({ name: 'nodes', - selectionSet: t.selectionSet({ selections }), - }), - ], - }), - }), - ], - }), - }), - ], + selectionSet: t.selectionSet({ selections }) + }) + ] + }) + }) + ] + }) + }) + ] }); return { document: print(document), variables }; @@ -339,15 +340,15 @@ export function buildCreateDocument( resultSelections: [ t.field({ name: entityField, - selectionSet: t.selectionSet({ selections }), - }), - ], + selectionSet: t.selectionSet({ selections }) + }) + ] }), variables: { input: { - [entityField]: data, - }, - }, + [entityField]: data + } + } }; } @@ -372,26 +373,117 @@ export function buildUpdateDocument( +export function buildUpdateByPkDocument( + operationName: string, + mutationField: string, + entityField: string, + select: TSelect, + id: string | number, + data: TData, + inputTypeName: string, + idFieldName: string +): { document: string; variables: Record } { + const selections = select + ? buildSelections(select as Record) + : [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 +): { document: string; variables: Record } { + const selections = select + ? buildSelections(select as Record) + : [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( operationName: string, mutationField: string, entityField: string, where: TWhere, - inputTypeName: string + inputTypeName: string, + select?: TSelect ): { document: string; variables: Record } { + const entitySelections = select + ? buildSelections(select as Record) + : [t.field({ name: 'id' })]; + return { document: buildInputMutationDocument({ operationName, @@ -401,16 +493,49 @@ export function buildDeleteDocument( t.field({ name: entityField, selectionSet: t.selectionSet({ - selections: [t.field({ name: 'id' })], - }), - }), - ], + selections: entitySelections + }) + }) + ] }), variables: { input: { - id: where.id, - }, - }, + id: where.id + } + } + }; +} + +export function buildDeleteByPkDocument( + operationName: string, + mutationField: string, + entityField: string, + id: string | number, + inputTypeName: string, + idFieldName: string, + select?: TSelect +): { document: string; variables: Record } { + const entitySelections = select + ? buildSelections(select as Record) + : [t.field({ name: 'id' })]; + + return { + document: buildInputMutationDocument({ + operationName, + mutationField, + inputTypeName, + resultSelections: [ + t.field({ + name: entityField, + selectionSet: t.selectionSet({ selections: entitySelections }) + }) + ] + }), + variables: { + input: { + [idFieldName]: id + } + } }; } @@ -440,13 +565,13 @@ export function buildCustomDocument( const variableDefs = variableDefinitions.map((definition) => t.variableDefinition({ variable: t.variable({ name: definition.name }), - type: parseType(definition.type), + type: parseType(definition.type) }) ); const fieldArgs = variableDefinitions.map((definition) => t.argument({ name: definition.name, - value: t.variable({ name: definition.name }), + value: t.variable({ name: definition.name }) }) ); @@ -467,17 +592,17 @@ export function buildCustomDocument( args: fieldArgs.length ? fieldArgs : undefined, selectionSet: fieldSelections.length ? t.selectionSet({ selections: fieldSelections }) - : undefined, - }), - ], - }), - }), - ], + : undefined + }) + ] + }) + }) + ] }); return { document: print(document), - variables: (args ?? {}) as Record, + variables: (args ?? {}) as Record }; } @@ -513,15 +638,15 @@ function buildEnumListArg( return t.argument({ name, value: t.listValue({ - values: values.map((value) => buildEnumValue(value)), - }), + values: values.map((value) => buildEnumValue(value)) + }) }); } function buildEnumValue(value: string): EnumValueNode { return { kind: 'EnumValue', - value, + value }; } @@ -530,7 +655,7 @@ function buildPageInfoSelections(): FieldNode[] { t.field({ name: 'hasNextPage' }), t.field({ name: 'hasPreviousPage' }), t.field({ name: 'startCursor' }), - t.field({ name: 'endCursor' }), + t.field({ name: 'endCursor' }) ]; } @@ -538,13 +663,13 @@ function buildConnectionSelections(nodeSelections: FieldNode[]): FieldNode[] { return [ t.field({ name: 'nodes', - selectionSet: t.selectionSet({ selections: nodeSelections }), + selectionSet: t.selectionSet({ selections: nodeSelections }) }), t.field({ name: 'totalCount' }), t.field({ name: 'pageInfo', - selectionSet: t.selectionSet({ selections: buildPageInfoSelections() }), - }), + selectionSet: t.selectionSet({ selections: buildPageInfoSelections() }) + }) ]; } @@ -571,8 +696,8 @@ function buildInputMutationDocument(config: InputMutationConfig): string { variableDefinitions: [ t.variableDefinition({ variable: t.variable({ name: 'input' }), - type: parseType(config.inputTypeName + '!'), - }), + type: parseType(config.inputTypeName + '!') + }) ], selectionSet: t.selectionSet({ selections: [ @@ -581,17 +706,17 @@ function buildInputMutationDocument(config: InputMutationConfig): string { args: [ t.argument({ name: 'input', - value: t.variable({ name: 'input' }), - }), + value: t.variable({ name: 'input' }) + }) ], selectionSet: t.selectionSet({ - selections: config.resultSelections, - }), - }), - ], - }), - }), - ], + selections: config.resultSelections + }) + }) + ] + }) + }) + ] }); return print(document); } @@ -607,13 +732,13 @@ function addVariable( definitions.push( t.variableDefinition({ variable: t.variable({ name: spec.varName }), - type: parseType(spec.typeName), + type: parseType(spec.typeName) }) ); args.push( t.argument({ name: spec.argName ?? spec.varName, - value: t.variable({ name: spec.varName }), + value: t.variable({ name: spec.varName }) }) ); variables[spec.varName] = spec.value; @@ -650,7 +775,7 @@ function buildValueAst( if (Array.isArray(value)) { return t.listValue({ - values: value.map((item) => buildValueAst(item)), + values: value.map((item) => buildValueAst(item)) }); } @@ -660,9 +785,9 @@ function buildValueAst( fields: Object.entries(obj).map(([key, val]) => t.objectField({ name: key, - value: buildValueAst(val), + 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..df14aac7b 100644 --- a/graphql/codegen/src/core/codegen/templates/select-types.ts +++ b/graphql/codegen/src/core/codegen/templates/select-types.ts @@ -48,8 +48,17 @@ 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; } /** diff --git a/graphql/codegen/src/core/codegen/type-resolver.ts b/graphql/codegen/src/core/codegen/type-resolver.ts index f358cff12..9e8856aa3 100644 --- a/graphql/codegen/src/core/codegen/type-resolver.ts +++ b/graphql/codegen/src/core/codegen/type-resolver.ts @@ -5,11 +5,10 @@ * into TypeScript type strings and interface definitions. */ import type { - CleanTypeRef, - CleanArgument, CleanObjectField, + CleanTypeRef } from '../../types/schema'; -import { scalarToTsType as resolveScalarToTs, SCALAR_NAMES } from './scalars'; +import { SCALAR_NAMES,scalarToTsType as resolveScalarToTs } from './scalars'; // ============================================================================ // Type Tracker for Collecting Referenced Types @@ -31,7 +30,7 @@ const SKIP_TYPE_TRACKING = new Set([ '__EnumValue', '__Directive', // Connection types (handled separately) - 'PageInfo', + 'PageInfo' ]); /** @@ -88,7 +87,7 @@ export function createTypeTracker(options?: TypeTrackerOptions): TypeTracker { }, reset() { referencedTypes.clear(); - }, + } }; } @@ -116,42 +115,42 @@ export function scalarToTsType(scalarName: string): string { */ export function typeRefToTsType(typeRef: CleanTypeRef, tracker?: TypeTracker): string { switch (typeRef.kind) { - case 'NON_NULL': - // Non-null wrapper - unwrap and return the inner type - if (typeRef.ofType) { - return typeRefToTsType(typeRef.ofType, tracker); - } - return 'unknown'; + case 'NON_NULL': + // Non-null wrapper - unwrap and return the inner type + if (typeRef.ofType) { + return typeRefToTsType(typeRef.ofType, tracker); + } + return 'unknown'; - case 'LIST': - // List wrapper - wrap inner type in array - if (typeRef.ofType) { - const innerType = typeRefToTsType(typeRef.ofType, tracker); - return `${innerType}[]`; - } - return 'unknown[]'; + case 'LIST': + // List wrapper - wrap inner type in array + if (typeRef.ofType) { + const innerType = typeRefToTsType(typeRef.ofType, tracker); + return `${innerType}[]`; + } + return 'unknown[]'; - case 'SCALAR': - // Scalar type - map to TS type - return scalarToTsType(typeRef.name ?? 'unknown'); + case 'SCALAR': + // Scalar type - map to TS type + return scalarToTsType(typeRef.name ?? 'unknown'); - case 'ENUM': { - // Enum type - use the GraphQL enum name and track it - const typeName = typeRef.name ?? 'string'; - tracker?.track(typeName); - return typeName; - } + case 'ENUM': { + // Enum type - use the GraphQL enum name and track it + const typeName = typeRef.name ?? 'string'; + tracker?.track(typeName); + return typeName; + } - case 'OBJECT': - case 'INPUT_OBJECT': { - // Object types - use the GraphQL type name and track it - const typeName = typeRef.name ?? 'unknown'; - tracker?.track(typeName); - return typeName; - } + case 'OBJECT': + case 'INPUT_OBJECT': { + // Object types - use the GraphQL type name and track it + const typeName = typeRef.name ?? 'unknown'; + tracker?.track(typeName); + return typeName; + } - default: - return 'unknown'; + default: + return 'unknown'; } } diff --git a/graphql/codegen/src/core/codegen/types.ts b/graphql/codegen/src/core/codegen/types.ts index 4491ed972..1fb93e70c 100644 --- a/graphql/codegen/src/core/codegen/types.ts +++ b/graphql/codegen/src/core/codegen/types.ts @@ -1,10 +1,11 @@ /** * 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; @@ -37,7 +38,7 @@ const FILTER_CONFIGS: Array<{ name: string; tsType: string; operators: FilterOps // 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: 'UUIDListFilter', tsType: 'string[]', operators: ['equality', 'distinct', 'comparison', 'listArray'] } ]; /** Build filter properties based on operator sets */ @@ -49,7 +50,7 @@ function buildFilterProperties(tsType: string, operators: FilterOps[]): Interfac 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 } ); } @@ -57,7 +58,7 @@ function buildFilterProperties(tsType: string, operators: FilterOps[]): Interfac if (operators.includes('distinct')) { props.push( { name: 'distinctFrom', type: tsType, optional: true }, - { name: 'notDistinctFrom', type: tsType, optional: true }, + { name: 'notDistinctFrom', type: tsType, optional: true } ); } @@ -65,7 +66,7 @@ function buildFilterProperties(tsType: string, operators: FilterOps[]): Interfac if (operators.includes('inArray')) { props.push( { name: 'in', type: `${tsType}[]`, optional: true }, - { name: 'notIn', type: `${tsType}[]`, optional: true }, + { name: 'notIn', type: `${tsType}[]`, optional: true } ); } @@ -75,7 +76,7 @@ function buildFilterProperties(tsType: string, operators: FilterOps[]): Interfac { 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 } ); } @@ -97,7 +98,7 @@ function buildFilterProperties(tsType: string, operators: FilterOps[]): Interfac { 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 } ); } @@ -108,7 +109,7 @@ function buildFilterProperties(tsType: string, operators: FilterOps[]): Interfac { name: 'containedBy', type: 'unknown', 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 } ); } @@ -117,7 +118,7 @@ function buildFilterProperties(tsType: string, operators: FilterOps[]): Interfac props.push( { name: 'contains', type: 'string', optional: true }, { name: 'containedBy', type: 'string', optional: true }, - { name: 'containsOrContainedBy', type: 'string', optional: true }, + { name: 'containsOrContainedBy', type: 'string', optional: true } ); } @@ -139,7 +140,7 @@ function buildFilterProperties(tsType: string, operators: FilterOps[]): Interfac { 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 } ); } @@ -237,7 +238,7 @@ export function generateTypesFile( const properties: InterfaceProperty[] = scalarFields.map((field) => ({ name: field.name, - type: `${fieldTypeToTs(field.type)} | null`, + type: `${fieldTypeToTs(field.type)} | null` })); statements.push(createInterfaceDeclaration(table.name, properties)); diff --git a/graphql/codegen/src/core/codegen/utils.ts b/graphql/codegen/src/core/codegen/utils.ts index dc46b8703..859a67900 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 @@ -77,7 +78,7 @@ export function getTableNames(table: CleanTable): TableNames { typeName, singularName, pluralName, - pluralTypeName, + pluralTypeName }; } @@ -360,8 +361,8 @@ export function getPrimaryKeyInfo(table: CleanTable): PrimaryKeyField[] { { name: idField.name, gqlType: idField.type.gqlType, - tsType: fieldTypeToTs(idField.type), - }, + tsType: fieldTypeToTs(idField.type) + } ]; } // Last resort: assume 'id' of type string (UUID) @@ -370,7 +371,7 @@ export function getPrimaryKeyInfo(table: CleanTable): PrimaryKeyField[] { return pk.fields.map((f) => ({ name: f.name, gqlType: f.type.gqlType, - tsType: fieldTypeToTs(f.type), + tsType: fieldTypeToTs(f.type) })); } @@ -400,6 +401,36 @@ export function hasValidPrimaryKey(table: CleanTable): boolean { return false; } +/** + * Get the best field name for a defaultSelect literal. + * Prefers PK field if valid, then 'id'/'nodeId', then first scalar field. + * Unlike getPrimaryKeyInfo(), never returns a fictional 'id' fallback. + */ +export function getDefaultSelectFieldName(table: CleanTable): string { + // 1. Try the actual primary key + const pk = table.constraints?.primaryKey?.[0]; + if (pk && pk.fields.length >= 1) { + return pk.fields[0].name; + } + // 2. Try id / nodeId fields + const idField = table.fields.find((f) => f.name === 'id' || f.name === 'nodeId'); + if (idField) { + return idField.name; + } + // 3. First non-array scalar field + const scalarField = table.fields.find( + (f) => !f.type.isArray && scalarToTsType(f.type.gqlType) !== f.type.gqlType + ); + if (scalarField) { + return scalarField.name; + } + // 4. First field of any kind + if (table.fields.length > 0) { + return table.fields[0].name; + } + return 'id'; +} + // ============================================================================ // Query key generation // ============================================================================ diff --git a/graphql/codegen/src/core/config/index.ts b/graphql/codegen/src/core/config/index.ts index 239e5581b..99dea07ad 100644 --- a/graphql/codegen/src/core/config/index.ts +++ b/graphql/codegen/src/core/config/index.ts @@ -6,12 +6,11 @@ export { CONFIG_FILENAME, findConfigFile, loadConfigFile, - type LoadConfigFileResult, + 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..668b3adc9 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'; @@ -55,7 +56,7 @@ export async function loadConfigFile( if (!fs.existsSync(resolvedPath)) { return { success: false, - error: `Config file not found: ${resolvedPath}`, + error: `Config file not found: ${resolvedPath}` }; } @@ -64,7 +65,7 @@ export async function loadConfigFile( // jiti handles .ts, .js, .mjs, .cjs and ESM/CJS interop const jiti = createJiti(__filename, { interopDefault: true, - debug: process.env.JITI_DEBUG === '1', + debug: process.env.JITI_DEBUG === '1' }); // jiti.import() with { default: true } returns mod?.default ?? mod @@ -73,19 +74,19 @@ export async function loadConfigFile( if (!config || typeof config !== 'object') { return { success: false, - error: 'Config file must export a configuration object', + error: 'Config file must export a configuration object' }; } return { success: true, - config, + config }; } catch (err) { const message = err instanceof Error ? err.message : 'Unknown error'; return { success: false, - error: `Failed to load config file: ${message}`, + error: `Failed to load config file: ${message}` }; } } diff --git a/graphql/codegen/src/core/config/resolver.ts b/graphql/codegen/src/core/config/resolver.ts index 56c551e3b..aa71fe60b 100644 --- a/graphql/codegen/src/core/config/resolver.ts +++ b/graphql/codegen/src/core/config/resolver.ts @@ -6,9 +6,9 @@ */ import type { GraphQLSDKConfig, - GraphQLSDKConfigTarget, + GraphQLSDKConfigTarget } from '../../types/config'; -import { mergeConfig, getConfigOptions } from '../../types/config'; +import { getConfigOptions,mergeConfig } from '../../types/config'; import { findConfigFile, loadConfigFile } from './loader'; /** @@ -47,13 +47,13 @@ export async function loadAndResolveConfig( const sources = [ overrides.endpoint, overrides.schemaFile, - overrides.db, + overrides.db ].filter(Boolean); if (sources.length > 1) { return { success: false, error: - 'Multiple sources specified. Use only one of: endpoint, schemaFile, or db.', + 'Multiple sources specified. Use only one of: endpoint, schemaFile, or db.' }; } @@ -85,13 +85,13 @@ export async function loadAndResolveConfig( return { success: false, error: - 'No source specified. Use --endpoint, --schema-file, or --db, or create a config file with "graphql-codegen init".', + 'No source specified. Use --endpoint, --schema-file, or --db, or create a config file with "graphql-codegen init".' }; } return { success: true, - config: getConfigOptions(mergedConfig), + config: getConfigOptions(mergedConfig) }; } @@ -134,12 +134,12 @@ export async function loadWatchConfig(options: { const watchOverrides: GraphQLSDKConfigTarget = { watch: { ...(options.pollInterval !== undefined && { - pollInterval: options.pollInterval, + pollInterval: options.pollInterval }), ...(options.debounce !== undefined && { debounce: options.debounce }), ...(options.touch !== undefined && { touchFile: options.touch }), - ...(options.clear !== undefined && { clearScreen: options.clear }), - }, + ...(options.clear !== undefined && { clearScreen: options.clear }) + } }; let mergedConfig = mergeConfig(baseConfig, sourceOverrides); diff --git a/graphql/codegen/src/core/custom-ast.ts b/graphql/codegen/src/core/custom-ast.ts index 5d9a1428e..02ea4642b 100644 --- a/graphql/codegen/src/core/custom-ast.ts +++ b/graphql/codegen/src/core/custom-ast.ts @@ -22,7 +22,7 @@ export function getCustomAst(fieldDefn?: MetaField): FieldNode | null { } return t.field({ - name: fieldDefn.name, + name: fieldDefn.name }); } @@ -57,7 +57,7 @@ export function getCustomAstForCleanField(field: CleanField): FieldNode { // Return simple field for scalar types return t.field({ - name, + name }); } @@ -72,7 +72,7 @@ export function requiresSubfieldSelection(field: CleanField): boolean { 'GeometryPoint', 'Interval', 'GeometryGeometryCollection', - 'GeoJSON', + 'GeoJSON' ]; return complexTypes.includes(gqlType); @@ -85,8 +85,8 @@ export function geometryPointAst(name: string): FieldNode { return t.field({ name, selectionSet: t.selectionSet({ - selections: toFieldArray(['x', 'y']), - }), + selections: toFieldArray(['x', 'y']) + }) }); } @@ -101,8 +101,8 @@ export function geometryCollectionAst(name: string): FieldNode { kind: 'NamedType', name: { kind: 'Name', - value: 'GeometryPoint', - }, + value: 'GeometryPoint' + } }, selectionSet: { kind: 'SelectionSet', @@ -111,18 +111,18 @@ export function geometryCollectionAst(name: string): FieldNode { kind: 'Field', name: { kind: 'Name', - value: 'x', - }, + value: 'x' + } }, { kind: 'Field', name: { kind: 'Name', - value: 'y', - }, - }, - ], - }, + value: 'y' + } + } + ] + } }; return t.field({ @@ -133,11 +133,11 @@ export function geometryCollectionAst(name: string): FieldNode { name: 'geometries', selectionSet: t.selectionSet({ // eslint-disable-next-line @typescript-eslint/no-explicit-any - selections: [inlineFragment as any], // gql-ast limitation with inline fragments - }), - }), - ], - }), + selections: [inlineFragment as any] // gql-ast limitation with inline fragments + }) + }) + ] + }) }); } @@ -148,8 +148,8 @@ export function geometryAst(name: string): FieldNode { return t.field({ name, selectionSet: t.selectionSet({ - selections: toFieldArray(['geojson']), - }), + selections: toFieldArray(['geojson']) + }) }); } @@ -166,9 +166,9 @@ export function intervalAst(name: string): FieldNode { 'minutes', 'months', 'seconds', - 'years', - ]), - }), + 'years' + ]) + }) }); } diff --git a/graphql/codegen/src/core/database/index.ts b/graphql/codegen/src/core/database/index.ts index 74c41cb03..0ca12ff14 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 { @@ -47,7 +48,7 @@ export async function buildSchemaFromDatabase( const sdl = await buildSchemaSDL({ database, schemas, - graphile: { pgSettings: async () => ({ role: 'administrator' }) }, + graphile: { pgSettings: async () => ({ role: 'administrator' }) } }); // Write schema to file @@ -74,6 +75,6 @@ export async function buildSchemaSDLFromDatabase(options: { return buildSchemaSDL({ database, schemas, - graphile: { pgSettings: async () => ({ role: 'administrator' }) }, + graphile: { pgSettings: async () => ({ role: 'administrator' }) } }); } diff --git a/graphql/codegen/src/core/generate.ts b/graphql/codegen/src/core/generate.ts index 51e679a2d..e73b34edc 100644 --- a/graphql/codegen/src/core/generate.ts +++ b/graphql/codegen/src/core/generate.ts @@ -6,15 +6,15 @@ */ import path from '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; @@ -44,14 +44,16 @@ export async function generate(options: GenerateOptions = {}): Promise t.name), - filesWritten: allFilesWritten, + filesWritten: allFilesWritten }; } diff --git a/graphql/codegen/src/core/index.ts b/graphql/codegen/src/core/index.ts index 5dbf3eb23..86a01af13 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..7cd561125 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; @@ -35,7 +36,7 @@ function makeRequest( resolve({ statusCode: res.statusCode || 0, statusMessage: res.statusMessage || '', - data, + data }); }); }); @@ -83,7 +84,7 @@ export async function fetchSchema( const requestHeaders: Record = { 'Content-Type': 'application/json', Accept: 'application/json', - ...headers, + ...headers }; if (authorization) { @@ -92,12 +93,12 @@ export async function fetchSchema( const body = JSON.stringify({ query: SCHEMA_INTROSPECTION_QUERY, - variables: {}, + variables: {} }); const requestOptions: http.RequestOptions = { method: 'POST', - headers: requestHeaders, + headers: requestHeaders }; try { @@ -107,7 +108,7 @@ export async function fetchSchema( return { success: false, error: `HTTP ${response.statusCode}: ${response.statusMessage}`, - statusCode: response.statusCode, + statusCode: response.statusCode }; } @@ -121,7 +122,7 @@ export async function fetchSchema( return { success: false, error: `GraphQL errors: ${errorMessages}`, - statusCode: response.statusCode, + statusCode: response.statusCode }; } @@ -130,21 +131,21 @@ export async function fetchSchema( success: false, error: 'No __schema field in response. Introspection may be disabled on this endpoint.', - statusCode: response.statusCode, + statusCode: response.statusCode }; } return { success: true, data: json.data, - statusCode: response.statusCode, + statusCode: response.statusCode }; } catch (err) { if (err instanceof Error) { if (err.message.includes('timeout')) { return { success: false, - error: `Request timeout after ${timeout}ms`, + error: `Request timeout after ${timeout}ms` }; } @@ -152,31 +153,31 @@ export async function fetchSchema( if (errorCode === 'ECONNREFUSED') { return { success: false, - error: `Connection refused - is the server running at ${endpoint}?`, + error: `Connection refused - is the server running at ${endpoint}?` }; } if (errorCode === 'ENOTFOUND') { return { success: false, - error: `DNS lookup failed for ${url.hostname} - check the endpoint URL`, + error: `DNS lookup failed for ${url.hostname} - check the endpoint URL` }; } if (errorCode === 'ECONNRESET') { return { success: false, - error: `Connection reset by server at ${endpoint}`, + error: `Connection reset by server at ${endpoint}` }; } return { success: false, - error: err.message, + error: err.message }; } return { success: false, - error: 'Unknown error occurred', + error: 'Unknown error occurred' }; } } diff --git a/graphql/codegen/src/core/introspect/index.ts b/graphql/codegen/src/core/introspect/index.ts index baaf7ebc2..5ddf28346 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..ef53092be 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, + 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, - TableInflection, - TableQueryNames, - TableConstraints, + CleanRelations, + CleanTable, ConstraintInfo, + TableConstraints, + TableInflection, + TableQueryNames } from '../../types/schema'; -import { singularize, pluralize, lcFirst, ucFirst } from 'inflekt'; // ============================================================================ // Pattern Matching Constants @@ -63,7 +64,7 @@ const PATTERNS = { // Mutation name patterns (camelCase) createMutation: /^create([A-Z][a-zA-Z0-9]*)$/, updateMutation: /^update([A-Z][a-zA-Z0-9]*)$/, - deleteMutation: /^delete([A-Z][a-zA-Z0-9]*)$/, + deleteMutation: /^delete([A-Z][a-zA-Z0-9]*)$/ }; /** @@ -88,7 +89,7 @@ const BUILTIN_TYPES = new Set([ 'Time', 'JSON', 'BigInt', - 'BigFloat', + 'BigFloat' ]); /** @@ -244,7 +245,7 @@ function buildCleanTable( one: queryOps.one ?? lcFirst(entityName), create: mutationOps.create ?? `create${entityName}`, update: mutationOps.update, - delete: mutationOps.delete, + delete: mutationOps.delete }; return { @@ -254,9 +255,9 @@ function buildCleanTable( relations, inflection, query, - constraints, + constraints }, - hasRealOperation, + hasRealOperation }; } @@ -295,7 +296,7 @@ function extractEntityFields( // Include scalar, enum, and other non-relation fields fields.push({ name: field.name, - type: convertToCleanFieldType(field.type), + type: convertToCleanFieldType(field.type) }); } @@ -324,7 +325,7 @@ function convertToCleanFieldType( return { gqlType: baseType.name ?? 'Unknown', - isArray, + isArray // PostgreSQL-specific fields are not available from introspection // They were optional anyway and not used by generators }; @@ -371,7 +372,7 @@ function inferRelations( isUnique: false, // Can't determine from introspection alone referencesTable: baseTypeName, type: baseTypeName, - keys: [], // Would need FK info to populate + keys: [] // Would need FK info to populate }); } } @@ -425,8 +426,8 @@ function inferHasManyOrManyToMany( fieldName: field.name, rightTable: actualEntityName, junctionTable, - type: connectionTypeName, - }, + type: connectionTypeName + } }; } @@ -437,8 +438,8 @@ function inferHasManyOrManyToMany( isUnique: false, referencedByTable: relatedEntityName, type: connectionTypeName, - keys: [], - }, + keys: [] + } }; } @@ -596,9 +597,9 @@ function inferConstraints( fields: [ { name: idField.name, - type: convertToCleanFieldType(idField.type), - }, - ], + type: convertToCleanFieldType(idField.type) + } + ] }); } } @@ -617,9 +618,9 @@ function inferConstraints( fields: [ { name: idField.name, - type: convertToCleanFieldType(idField.type), - }, - ], + type: convertToCleanFieldType(idField.type) + } + ] }); } } @@ -628,7 +629,7 @@ function inferConstraints( return { primaryKey, foreignKey: [], // Would need FK info to populate - unique: [], // Would need constraint info to populate + unique: [] // Would need constraint info to populate }; } @@ -681,7 +682,7 @@ function buildInflection( tableType: entityName, typeName: entityName, updateByPrimaryKey: `update${entityName}`, - updatePayloadType: hasUpdatePayload ? `Update${entityName}Payload` : null, + updatePayloadType: hasUpdatePayload ? `Update${entityName}Payload` : null }; } @@ -710,7 +711,7 @@ function findOrderByType( const candidates = [ `${entityName}sOrderBy`, // Simple 's' plural: User -> UsersOrderBy `${entityName}esOrderBy`, // 'es' plural: Address -> AddressesOrderBy - `${entityName}OrderBy`, // No change (already plural or singular OK) + `${entityName}OrderBy` // No change (already plural or singular OK) ]; // Check each candidate diff --git a/graphql/codegen/src/core/introspect/source/api-schemas.ts b/graphql/codegen/src/core/introspect/source/api-schemas.ts index 4ff79229f..4b81f5280 100644 --- a/graphql/codegen/src/core/introspect/source/api-schemas.ts +++ b/graphql/codegen/src/core/introspect/source/api-schemas.ts @@ -39,7 +39,7 @@ 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 +52,7 @@ 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 +65,7 @@ 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.' }; } @@ -73,7 +73,7 @@ export async function validateServicesSchemas( } catch (err) { return { valid: false, - error: `Failed to validate services schemas: ${err instanceof Error ? err.message : 'Unknown error'}`, + error: `Failed to validate services schemas: ${err instanceof Error ? err.message : 'Unknown error'}` }; } } @@ -142,7 +142,7 @@ export function createDatabasePool(database: string): Pool { port: parseInt(url.port || '5432', 10), user: url.username, password: url.password, - database: dbName, + database: dbName }); } diff --git a/graphql/codegen/src/core/introspect/source/database.ts b/graphql/codegen/src/core/introspect/source/database.ts index 4b77ea12e..55dfb0355 100644 --- a/graphql/codegen/src/core/introspect/source/database.ts +++ b/graphql/codegen/src/core/introspect/source/database.ts @@ -5,11 +5,12 @@ * 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 type { SchemaSource, SchemaSourceResult } from './types'; +import { SchemaSourceError } from './types'; export interface DatabaseSchemaSourceOptions { /** @@ -77,7 +78,7 @@ export class DatabaseSchemaSource implements SchemaSource { try { sdl = await buildSchemaSDLFromDatabase({ database, - schemas, + schemas }); } catch (err) { throw new SchemaSourceError( diff --git a/graphql/codegen/src/core/introspect/source/endpoint.ts b/graphql/codegen/src/core/introspect/source/endpoint.ts index a5c50ff84..20ec8d931 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 { /** @@ -45,7 +45,7 @@ export class EndpointSchemaSource implements SchemaSource { endpoint: this.options.endpoint, authorization: this.options.authorization, headers: this.options.headers, - timeout: this.options.timeout, + timeout: this.options.timeout }); if (!result.success) { @@ -63,7 +63,7 @@ export class EndpointSchemaSource implements SchemaSource { } return { - introspection: result.data, + introspection: result.data }; } diff --git a/graphql/codegen/src/core/introspect/source/file.ts b/graphql/codegen/src/core/introspect/source/file.ts index 6ab828aac..58ffe6b33 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 { /** diff --git a/graphql/codegen/src/core/introspect/source/index.ts b/graphql/codegen/src/core/introspect/source/index.ts index 9642201c0..c96b498be 100644 --- a/graphql/codegen/src/core/introspect/source/index.ts +++ b/graphql/codegen/src/core/introspect/source/index.ts @@ -7,23 +7,21 @@ * - 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, + PgpmModuleSchemaSource } from './pgpm-module'; +import type { SchemaSource } from './types'; /** * Options for endpoint-based schema source @@ -142,49 +140,49 @@ export function createSchemaSource( const mode = detectSourceMode(options); switch (mode) { - case 'schemaFile': - return new FileSchemaSource({ - schemaPath: options.schemaFile!, - }); + case 'schemaFile': + return new FileSchemaSource({ + schemaPath: options.schemaFile! + }); - case 'endpoint': - return new EndpointSchemaSource({ - endpoint: options.endpoint!, - authorization: options.authorization, - headers: options.headers, - timeout: options.timeout, - }); + case 'endpoint': + return new EndpointSchemaSource({ + endpoint: options.endpoint!, + authorization: options.authorization, + headers: options.headers, + timeout: options.timeout + }); - case 'database': - // Database mode uses db.config for connection (falls back to env vars) - // and db.schemas or db.apiNames for schema selection - return new DatabaseSchemaSource({ - database: options.db?.config?.database ?? '', - schemas: options.db?.schemas, - apiNames: options.db?.apiNames, - }); + case 'database': + // Database mode uses db.config for connection (falls back to env vars) + // and db.schemas or db.apiNames for schema selection + return new DatabaseSchemaSource({ + database: options.db?.config?.database ?? '', + schemas: options.db?.schemas, + apiNames: options.db?.apiNames + }); - case 'pgpm-module': - return new PgpmModuleSchemaSource({ - pgpmModulePath: options.db!.pgpm!.modulePath!, - schemas: options.db?.schemas, - apiNames: options.db?.apiNames, - keepDb: options.db?.keepDb, - }); + case 'pgpm-module': + return new PgpmModuleSchemaSource({ + pgpmModulePath: options.db!.pgpm!.modulePath!, + schemas: options.db?.schemas, + apiNames: options.db?.apiNames, + keepDb: options.db?.keepDb + }); - case 'pgpm-workspace': - return new PgpmModuleSchemaSource({ - pgpmWorkspacePath: options.db!.pgpm!.workspacePath!, - pgpmModuleName: options.db!.pgpm!.moduleName!, - schemas: options.db?.schemas, - apiNames: options.db?.apiNames, - keepDb: options.db?.keepDb, - }); + case 'pgpm-workspace': + return new PgpmModuleSchemaSource({ + pgpmWorkspacePath: options.db!.pgpm!.workspacePath!, + pgpmModuleName: options.db!.pgpm!.moduleName!, + schemas: options.db?.schemas, + apiNames: options.db?.apiNames, + keepDb: options.db?.keepDb + }); - default: - throw new Error( - 'No source specified. Use one of: endpoint, schemaFile, or db (with optional pgpm for module deployment).' - ); + default: + throw new Error( + 'No source specified. Use one of: endpoint, schemaFile, or db (with optional pgpm for module deployment).' + ); } } @@ -199,14 +197,14 @@ export function validateSourceOptions(options: CreateSchemaSourceOptions): { const sources = [ options.endpoint, options.schemaFile, - options.db, + options.db ].filter(Boolean); if (sources.length === 0) { return { valid: false, error: - 'No source specified. Use one of: endpoint, schemaFile, or db.', + 'No source specified. Use one of: endpoint, schemaFile, or db.' }; } @@ -214,7 +212,7 @@ export function validateSourceOptions(options: CreateSchemaSourceOptions): { return { valid: false, error: - 'Multiple sources specified. Use only one of: endpoint, schemaFile, or db.', + 'Multiple sources specified. Use only one of: endpoint, schemaFile, or db.' }; } @@ -224,14 +222,14 @@ 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 +237,7 @@ 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 +250,14 @@ 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..4bbc7e14e 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 @@ -147,7 +147,7 @@ export class PgpmModuleSchemaSource implements SchemaSource { try { this.ephemeralDb = createEphemeralDb({ prefix: 'codegen_pgpm_', - verbose: false, + verbose: false }); } catch (err) { throw new SchemaSourceError( @@ -199,7 +199,7 @@ export class PgpmModuleSchemaSource implements SchemaSource { try { sdl = await buildSchemaSDLFromDatabase({ database: dbConfig.database, - schemas, + schemas }); } catch (err) { throw new SchemaSourceError( diff --git a/graphql/codegen/src/core/introspect/transform-schema.ts b/graphql/codegen/src/core/introspect/transform-schema.ts index 40cc4aa9f..a7edd5216 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 { - IntrospectionQueryResponse, - IntrospectionType, IntrospectionField, - IntrospectionTypeRef, IntrospectionInputValue, + IntrospectionQueryResponse, + IntrospectionType, + IntrospectionTypeRef } 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'; // ============================================================================ @@ -48,7 +48,7 @@ export function buildTypeRegistry(types: IntrospectionType[]): TypeRegistry { const resolvedType: ResolvedType = { kind: type.kind as ResolvedType['kind'], name: type.name, - description: type.description ?? undefined, + description: type.description ?? undefined }; // Resolve enum values for ENUM types (no circular refs possible) @@ -99,7 +99,7 @@ function transformFieldToCleanObjectFieldShallow( return { name: field.name, type: transformTypeRefShallow(field.type), - description: field.description ?? undefined, + description: field.description ?? undefined }; } @@ -113,7 +113,7 @@ function transformInputValueToCleanArgumentShallow( name: inputValue.name, type: transformTypeRefShallow(inputValue.type), defaultValue: inputValue.defaultValue ?? undefined, - description: inputValue.description ?? undefined, + description: inputValue.description ?? undefined }; } @@ -124,7 +124,7 @@ function transformInputValueToCleanArgumentShallow( function transformTypeRefShallow(typeRef: IntrospectionTypeRef): CleanTypeRef { const cleanRef: CleanTypeRef = { kind: typeRef.kind as CleanTypeRef['kind'], - name: typeRef.name, + name: typeRef.name }; if (typeRef.ofType) { @@ -165,15 +165,15 @@ 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) + ) : []; return { queries, mutations, typeRegistry }; @@ -200,7 +200,7 @@ function transformFieldToCleanOperation( returnType: transformTypeRefToCleanTypeRef(field.type, types), description: field.description ?? undefined, isDeprecated: field.isDeprecated, - deprecationReason: field.deprecationReason ?? undefined, + deprecationReason: field.deprecationReason ?? undefined }; } @@ -215,7 +215,7 @@ function transformInputValueToCleanArgument( name: inputValue.name, type: transformTypeRefToCleanTypeRef(inputValue.type, types), defaultValue: inputValue.defaultValue ?? undefined, - description: inputValue.description ?? undefined, + description: inputValue.description ?? undefined }; } @@ -237,7 +237,7 @@ function transformTypeRefToCleanTypeRef( ): CleanTypeRef { const cleanRef: CleanTypeRef = { kind: typeRef.kind as CleanTypeRef['kind'], - name: typeRef.name, + name: typeRef.name }; // Recursively transform ofType for wrappers (LIST, NON_NULL) @@ -400,4 +400,4 @@ export function getCustomOperations( } // Re-export utility functions from introspection types -export { unwrapType, getBaseTypeName, isNonNull }; +export { getBaseTypeName, isNonNull,unwrapType }; diff --git a/graphql/codegen/src/core/meta-object/convert.ts b/graphql/codegen/src/core/meta-object/convert.ts index 02bff2fe4..295ae7841 100644 --- a/graphql/codegen/src/core/meta-object/convert.ts +++ b/graphql/codegen/src/core/meta-object/convert.ts @@ -78,11 +78,11 @@ export function convertFromMetaSchema( metaSchema: MetaSchemaInput ): ConvertedMetaObject { const { - _meta: { tables }, + _meta: { tables } } = metaSchema; const result: ConvertedMetaObject = { - tables: [], + tables: [] }; for (const table of tables) { @@ -94,7 +94,7 @@ export function convertFromMetaSchema( foreignConstraints: pickForeignConstraint( table.foreignKeyConstraints, table.relations - ), + ) }); } @@ -136,7 +136,7 @@ function pickForeignConstraint( return { refTable: refTable.name, fromKey, - toKey, + toKey }; }); } @@ -144,13 +144,13 @@ function pickForeignConstraint( function pickField(field: MetaSchemaField): ConvertedField { return { name: field.name, - type: field.type, + type: field.type }; } function pickConstraintField(field: MetaSchemaField): ConvertedConstraint { return { name: field.name, - type: field.type, + type: field.type }; } diff --git a/graphql/codegen/src/core/meta-object/validate.ts b/graphql/codegen/src/core/meta-object/validate.ts index 1481e6b5d..eab7a346b 100644 --- a/graphql/codegen/src/core/meta-object/validate.ts +++ b/graphql/codegen/src/core/meta-object/validate.ts @@ -18,7 +18,7 @@ function getValidator() { return { ajv: cachedAjv, - validator: cachedValidator!, + validator: cachedValidator! }; } @@ -36,6 +36,6 @@ export function validateMetaObject( return { errors: validator.errors, - message: ajv.errorsText(validator.errors, { separator: '\n' }), + message: ajv.errorsText(validator.errors, { separator: '\n' }) }; } diff --git a/graphql/codegen/src/core/output/index.ts b/graphql/codegen/src/core/output/index.ts index 3d6344d9c..529f10e41 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..8b04f1613 100644 --- a/graphql/codegen/src/core/output/writer.ts +++ b/graphql/codegen/src/core/output/writer.ts @@ -62,7 +62,7 @@ async function formatFileContent( singleQuote: true, trailingComma: 'es5', tabWidth: 2, - semi: true, + semi: true }); return result.code; } catch { @@ -98,7 +98,7 @@ export async function writeGeneratedFiles( const message = err instanceof Error ? err.message : 'Unknown error'; return { success: false, - errors: [`Failed to create output directory: ${message}`], + errors: [`Failed to create output directory: ${message}`] }; } @@ -171,7 +171,7 @@ export async function writeGeneratedFiles( return { success: errors.length === 0, filesWritten: written, - errors: errors.length > 0 ? errors : undefined, + errors: errors.length > 0 ? errors : undefined }; } @@ -211,7 +211,7 @@ export async function formatOutput( if (!formatFn) { return { success: false, - error: 'oxfmt not available. Install it with: npm install oxfmt', + error: 'oxfmt not available. Install it with: npm install oxfmt' }; } diff --git a/graphql/codegen/src/core/pipeline/index.ts b/graphql/codegen/src/core/pipeline/index.ts index 65aba4e21..f2d33456d 100644 --- a/graphql/codegen/src/core/pipeline/index.ts +++ b/graphql/codegen/src/core/pipeline/index.ts @@ -10,18 +10,18 @@ */ import type { GraphQLSDKConfigTarget } from '../../types/config'; import type { - CleanTable, CleanOperation, - TypeRegistry, + 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 @@ -103,7 +103,7 @@ export async function runCodegenPipeline( source, config, verbose = false, - skipCustomOperations = false, + skipCustomOperations = false } = options; const log = verbose ? console.log : () => {}; @@ -120,7 +120,7 @@ export async function runCodegenPipeline( // 3. Filter tables by config (combine exclude and systemExclude) tables = filterTables(tables, config.tables.include, [ ...config.tables.exclude, - ...config.tables.systemExclude, + ...config.tables.systemExclude ]); const filteredTables = tables.length; log(` After filtering: ${filteredTables} tables`); @@ -130,7 +130,7 @@ export async function runCodegenPipeline( const { queries: allQueries, mutations: allMutations, - typeRegistry, + typeRegistry } = transformSchemaToOperations(introspection); const totalQueries = allQueries.length; @@ -178,7 +178,7 @@ export async function runCodegenPipeline( customOperations: { queries: customQueries, mutations: customMutations, - typeRegistry, + typeRegistry }, stats: { totalTables, @@ -186,8 +186,8 @@ export async function runCodegenPipeline( totalQueries, totalMutations, customQueries: customQueries.length, - customMutations: customMutations.length, - }, + customMutations: customMutations.length + } }; } @@ -206,7 +206,7 @@ export function validateTablesFound(tables: CleanTable[]): { return { valid: false, error: - 'No tables found after filtering. Check your include/exclude patterns.', + 'No tables found after filtering. Check your include/exclude patterns.' }; } return { valid: true }; diff --git a/graphql/codegen/src/core/query-builder.ts b/graphql/codegen/src/core/query-builder.ts index 8be4db4ca..403ed2e3b 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, @@ -8,11 +8,10 @@ import { getCount, getMany, getOne, - patchOne, + patchOne } from './ast'; import { validateMetaObject } from './meta-object'; import type { - QueryFieldSelection, IntrospectionSchema, MetaObject, MetaTable, @@ -20,7 +19,8 @@ import type { QueryBuilderOptions, QueryBuilderResult, QueryDefinition, - QuerySelectionOptions, + QueryFieldSelection, + QuerySelectionOptions } from './types'; export * as MetaObject from './meta-object'; @@ -46,7 +46,7 @@ export class QueryBuilder { constructor({ meta = {} as MetaObject, - introspection, + introspection }: QueryBuilderOptions) { this._introspection = introspection; this._meta = meta; @@ -144,17 +144,17 @@ export class QueryBuilder { // We only need deleteAction from all of [deleteAction, deleteActionBySlug, deleteActionByName] const getInputName = (mutationType: string): string => { switch (mutationType) { - case 'delete': { - return `Delete${camelize(this._model)}Input`; - } - case 'create': { - return `Create${camelize(this._model)}Input`; - } - case 'patch': { - return `Update${camelize(this._model)}Input`; - } - default: - throw new Error('Unhandled mutation type' + mutationType); + case 'delete': { + return `Delete${camelize(this._model)}Input`; + } + case 'create': { + return `Create${camelize(this._model)}Input`; + } + case 'patch': { + return `Update${camelize(this._model)}Input`; + } + default: + throw new Error('Unhandled mutation type' + mutationType); } }; @@ -208,7 +208,7 @@ export class QueryBuilder { queryName: this._queryName, operationName: this._key, query: defn, - selection: this._select, + selection: this._select }); return this; @@ -232,7 +232,7 @@ export class QueryBuilder { queryName: this._queryName, operationName: this._key, query: defn, - selection: this._select, + selection: this._select }); return this; @@ -254,7 +254,7 @@ export class QueryBuilder { this._ast = getCount({ queryName: this._queryName, operationName: this._key, - query: defn, + query: defn }); return this; @@ -278,7 +278,7 @@ export class QueryBuilder { queryName: this._queryName, operationName: this._key, query: defn, - selection: this._select, + selection: this._select }); return this; @@ -302,7 +302,7 @@ export class QueryBuilder { operationName: this._key, mutationName: this._queryName, mutation: defn, - selection: this._select, + selection: this._select }); return this; @@ -326,7 +326,7 @@ export class QueryBuilder { this._ast = deleteOne({ operationName: this._key, mutationName: this._queryName, - mutation: defn, + mutation: defn }); return this; @@ -351,7 +351,7 @@ export class QueryBuilder { operationName: this._key, mutationName: this._queryName, mutation: defn, - selection: this._select, + selection: this._select }); return this; @@ -370,7 +370,7 @@ export class QueryBuilder { return { _hash, _queryName: this._queryName, - _ast: this._ast, + _ast: this._ast }; } @@ -421,7 +421,7 @@ function pickScalarFields( .map((fieldName) => ({ name: fieldName, isObject: false, - fieldDefn: modelMeta.fields.find((f) => f.name === fieldName), + fieldDefn: modelMeta.fields.find((f) => f.name === fieldName) })); // This is for inferring the sub-selection of a mutation query @@ -498,7 +498,7 @@ function pickAllFields( isObject: true, isBelongTo, selection: subFields.map((name) => ({ name, isObject: false })), - variables: selectOptions.variables as QueryFieldSelection['variables'], + variables: selectOptions.variables as QueryFieldSelection['variables'] }; // Need to further expand selection of object fields, @@ -529,8 +529,8 @@ function pickAllFields( { name: fieldName, isObject: false, - fieldDefn: modelMeta.fields.find((f) => f.name === fieldName), - }, + fieldDefn: modelMeta.fields.find((f) => f.name === fieldName) + } ]; } } diff --git a/graphql/codegen/src/core/watch/cache.ts b/graphql/codegen/src/core/watch/cache.ts index f92764d02..2df07bc6d 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'; diff --git a/graphql/codegen/src/core/watch/index.ts b/graphql/codegen/src/core/watch/index.ts index 6e220682f..737f372d6 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 { - PollResult, - WatchOptions, - PollEventType, - PollEventHandler, - PollEvent, GeneratorType, + PollEvent, + PollEventHandler, + PollEventType, + PollResult, + WatchOptions } 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..dc986a441 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 @@ -82,7 +82,7 @@ export class WatchOrchestrator { lastPollTime: null, lastRegenTime: null, lastError: null, - currentHash: null, + currentHash: null }; // Create debounced regenerate function @@ -105,7 +105,7 @@ export class WatchOrchestrator { debounce: config.watch.debounce, touchFile: config.watch.touchFile, clearScreen: config.watch.clearScreen, - verbose, + verbose }; } @@ -217,18 +217,18 @@ export class WatchOrchestrator { let outputDir: string | undefined; switch (this.options.generatorType) { - case 'react-query': - generateFn = this.options.generateReactQuery; - // React Query hooks go to {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`; - break; - default: - throw new Error(`Unknown generator type: ${this.options.generatorType}`); + case 'react-query': + generateFn = this.options.generateReactQuery; + // React Query hooks go to {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`; + break; + default: + throw new Error(`Unknown generator type: ${this.options.generatorType}`); } const result = await generateFn({ @@ -238,7 +238,7 @@ export class WatchOrchestrator { output: outputDir, authorization: this.options.authorization, verbose: this.watchOptions.verbose, - skipCustomOperations: this.options.skipCustomOperations, + skipCustomOperations: this.options.skipCustomOperations }); const duration = Date.now() - startTime; @@ -287,14 +287,14 @@ export class WatchOrchestrator { private logHeader(): void { let generatorName: string; switch (this.options.generatorType) { - case 'react-query': - generatorName = 'React Query hooks'; - break; - case 'orm': - generatorName = 'ORM client'; - break; - default: - throw new Error(`Unknown generator type: ${this.options.generatorType}`); + case 'react-query': + generatorName = 'React Query hooks'; + break; + case 'orm': + generatorName = 'ORM client'; + break; + default: + throw new Error(`Unknown generator type: ${this.options.generatorType}`); } console.log(`\n${'─'.repeat(50)}`); console.log(`graphql-codegen watch mode (${generatorName})`); diff --git a/graphql/codegen/src/core/watch/poller.ts b/graphql/codegen/src/core/watch/poller.ts index c60583f85..78e2937ac 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, - WatchOptions, + PollResult, + WatchOptions } from './types'; -import { hashObject } from './hash'; /** * Schema poller that periodically introspects a GraphQL endpoint @@ -73,7 +74,7 @@ export class SchemaPoller extends EventEmitter { return { success: false, changed: false, - error: 'Poll already in progress', + error: 'Poll already in progress' }; } @@ -87,7 +88,7 @@ export class SchemaPoller extends EventEmitter { endpoint: this.options.endpoint, authorization: this.options.authorization, headers: this.options.headers, - timeout: 30000, + timeout: 30000 }); const duration = Date.now() - startTime; @@ -156,7 +157,7 @@ export class SchemaPoller extends EventEmitter { endpoint: this.options.endpoint, authorization: this.options.authorization, headers: this.options.headers, - timeout: 30000, + timeout: 30000 }); if (schemaResult.success) { @@ -218,7 +219,7 @@ export class SchemaPoller extends EventEmitter { return { type, timestamp: Date.now(), - ...extra, + ...extra }; } } diff --git a/graphql/codegen/src/generators/field-selector.ts b/graphql/codegen/src/generators/field-selector.ts index 8e42e5c9d..43ce4851c 100644 --- a/graphql/codegen/src/generators/field-selector.ts +++ b/graphql/codegen/src/generators/field-selector.ts @@ -7,7 +7,7 @@ import type { CleanTable } from '../types/schema'; import type { FieldSelection, FieldSelectionPreset, - SimpleFieldSelection, + SimpleFieldSelection } from '../types/selection'; /** @@ -39,47 +39,47 @@ function convertPresetToSelection( const options: QuerySelectionOptions = {}; switch (preset) { - case 'minimal': { - // Just id and first display field - const minimalFields = getMinimalFields(table); - minimalFields.forEach((field) => { - options[field] = true; - }); - break; - } + case 'minimal': { + // Just id and first display field + const minimalFields = getMinimalFields(table); + minimalFields.forEach((field) => { + options[field] = true; + }); + break; + } - case 'display': { - // Common display fields - const displayFields = getDisplayFields(table); - displayFields.forEach((field) => { - options[field] = true; - }); - break; - } + case 'display': { + // Common display fields + const displayFields = getDisplayFields(table); + displayFields.forEach((field) => { + options[field] = true; + }); + break; + } - case 'all': { - // All non-relational fields (includes complex fields like JSON, geometry, etc.) - const allFields = getNonRelationalFields(table); - allFields.forEach((field) => { - options[field] = true; - }); - break; - } + case 'all': { + // All non-relational fields (includes complex fields like JSON, geometry, etc.) + const allFields = getNonRelationalFields(table); + allFields.forEach((field) => { + options[field] = true; + }); + break; + } - case 'full': - // All fields including basic relations - table.fields.forEach((field) => { - options[field.name] = true; - }); - break; + case 'full': + // All fields including basic relations + table.fields.forEach((field) => { + options[field.name] = true; + }); + break; - default: { - // Default to display - const defaultFields = getDisplayFields(table); - defaultFields.forEach((field) => { - options[field] = true; - }); - } + default: { + // Default to display + const defaultFields = getDisplayFields(table); + defaultFields.forEach((field) => { + options[field] = true; + }); + } } return options; @@ -118,7 +118,7 @@ function convertCustomSelectionToOptions( // Include with dynamically determined scalar fields from the related table options[relationField] = { select: getRelatedTableScalarFields(relationField, table, allTables), - variables: {}, + variables: {} }; } }); @@ -137,7 +137,7 @@ function convertCustomSelectionToOptions( table, allTables ), - variables: {}, + variables: {} }; } else if (Array.isArray(relationSelection)) { // Include with specific fields @@ -147,7 +147,7 @@ function convertCustomSelectionToOptions( }); options[relationField] = { select: selectObj, - variables: {}, + variables: {} }; } } @@ -305,7 +305,7 @@ function getRelatedTableScalarFields( 'slug', 'code', 'createdAt', - 'updatedAt', + 'updatedAt' ]; const included: string[] = []; @@ -351,7 +351,7 @@ export function getAvailableRelations( relations.push({ fieldName: rel.fieldName, type: 'belongsTo', - referencedTable: rel.referencesTable || undefined, + referencedTable: rel.referencesTable || undefined }); } }); @@ -362,7 +362,7 @@ export function getAvailableRelations( relations.push({ fieldName: rel.fieldName, type: 'hasOne', - referencedTable: rel.referencedByTable || undefined, + referencedTable: rel.referencedByTable || undefined }); } }); @@ -373,7 +373,7 @@ export function getAvailableRelations( relations.push({ fieldName: rel.fieldName, type: 'hasMany', - referencedTable: rel.referencedByTable || undefined, + referencedTable: rel.referencedByTable || undefined }); } }); @@ -384,7 +384,7 @@ export function getAvailableRelations( relations.push({ fieldName: rel.fieldName, type: 'manyToMany', - referencedTable: rel.rightTable || undefined, + referencedTable: rel.rightTable || undefined }); } }); @@ -465,6 +465,6 @@ export function validateFieldSelection( return { isValid: errors.length === 0, - errors, + errors }; } diff --git a/graphql/codegen/src/generators/index.ts b/graphql/codegen/src/generators/index.ts index 1bc3c755e..4b38b3518 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, - validateFieldSelection, + 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..3d86856e1 100644 --- a/graphql/codegen/src/generators/mutations.ts +++ b/graphql/codegen/src/generators/mutations.ts @@ -3,18 +3,17 @@ * 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'; import { getCustomAstForCleanField, - requiresSubfieldSelection, + 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'; /** @@ -55,17 +54,17 @@ export function buildPostGraphileCreate( t.variableDefinition({ variable: t.variable({ name: 'input' }), type: t.nonNullType({ - type: t.namedType({ type: `Create${table.name}Input` }), - }), - }), + type: t.namedType({ type: `Create${table.name}Input` }) + }) + }) ]; // Create the mutation arguments const mutationArgs: ArgumentNode[] = [ t.argument({ name: 'input', - value: t.variable({ name: 'input' }), - }), + value: t.variable({ name: 'input' }) + }) ]; // Get the field selections for the return value using custom AST logic @@ -88,23 +87,23 @@ export function buildPostGraphileCreate( t.field({ name: singularName, selectionSet: t.selectionSet({ - selections: fieldSelections, - }), - }), - ], - }), - }), - ], - }), - }), - ], + selections: fieldSelections + }) + }) + ] + }) + }) + ] + }) + }) + ] }); // Print the AST to get the query string const queryString = print(ast); return new TypedDocumentString(queryString, { - __ast: ast, + __ast: ast }) as TypedDocumentString< Record, { input: { [key: string]: Record } } @@ -131,17 +130,17 @@ export function buildPostGraphileUpdate( t.variableDefinition({ variable: t.variable({ name: 'input' }), type: t.nonNullType({ - type: t.namedType({ type: `Update${table.name}Input` }), - }), - }), + type: t.namedType({ type: `Update${table.name}Input` }) + }) + }) ]; // Create the mutation arguments const mutationArgs: ArgumentNode[] = [ t.argument({ name: 'input', - value: t.variable({ name: 'input' }), - }), + value: t.variable({ name: 'input' }) + }) ]; // Get the field selections for the return value using custom AST logic @@ -164,23 +163,23 @@ export function buildPostGraphileUpdate( t.field({ name: singularName, selectionSet: t.selectionSet({ - selections: fieldSelections, - }), - }), - ], - }), - }), - ], - }), - }), - ], + selections: fieldSelections + }) + }) + ] + }) + }) + ] + }) + }) + ] }); // Print the AST to get the query string const queryString = print(ast); return new TypedDocumentString(queryString, { - __ast: ast, + __ast: ast }) as TypedDocumentString< Record, { input: { id: string | number; patch: Record } } @@ -206,17 +205,17 @@ export function buildPostGraphileDelete( t.variableDefinition({ variable: t.variable({ name: 'input' }), type: t.nonNullType({ - type: t.namedType({ type: `Delete${table.name}Input` }), - }), - }), + type: t.namedType({ type: `Delete${table.name}Input` }) + }) + }) ]; // Create the mutation arguments const mutationArgs: ArgumentNode[] = [ t.argument({ name: 'input', - value: t.variable({ name: 'input' }), - }), + value: t.variable({ name: 'input' }) + }) ]; // PostGraphile delete mutations typically return clientMutationId @@ -235,20 +234,20 @@ export function buildPostGraphileDelete( name: mutationName, args: mutationArgs, selectionSet: t.selectionSet({ - selections: fieldSelections, - }), - }), - ], - }), - }), - ], + selections: fieldSelections + }) + }) + ] + }) + }) + ] }); // Print the AST to get the query string const queryString = print(ast); return new TypedDocumentString(queryString, { - __ast: ast, + __ast: ast }) as TypedDocumentString< Record, { input: { id: string | number } } diff --git a/graphql/codegen/src/generators/select.ts b/graphql/codegen/src/generators/select.ts index edf2cace7..8bd58ccf8 100644 --- a/graphql/codegen/src/generators/select.ts +++ b/graphql/codegen/src/generators/select.ts @@ -3,14 +3,14 @@ * 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'; import { getCustomAstForCleanField, - requiresSubfieldSelection, + requiresSubfieldSelection } from '../core/custom-ast'; import { QueryBuilder } from '../core/query-builder'; import type { @@ -20,12 +20,11 @@ import type { MetaObject, MutationDefinition, QueryDefinition, - QuerySelectionOptions, + 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'; /** @@ -67,8 +66,8 @@ export function cleanTableToMetaObject(tables: CleanTable[]): MetaObject { pgAlias: field.type.pgAlias, pgType: field.type.pgType, subtype: field.type.subtype, - typmod: field.type.typmod, - }, + typmod: field.type.typmod + } })), primaryConstraints: [] as MetaConstraint[], // Would need to be derived from schema uniqueConstraints: [] as MetaConstraint[], // Would need to be derived from schema @@ -83,9 +82,9 @@ export function cleanTableToMetaObject(tables: CleanTable[]): MetaObject { pgAlias: null, pgType: null, subtype: null, - typmod: null, + typmod: null } as MetaFieldType, - alias: rel.fieldName || '', + alias: rel.fieldName || '' }, toKey: { name: 'id', @@ -96,11 +95,11 @@ export function cleanTableToMetaObject(tables: CleanTable[]): MetaObject { pgAlias: null, pgType: null, subtype: null, - typmod: null, - } as MetaFieldType, - }, - })), - })), + typmod: null + } as MetaFieldType + } + })) + })) }; } @@ -125,7 +124,7 @@ export function generateIntrospectionSchema( qtype: 'getMany', model: modelName, selection, - properties: convertFieldsToProperties(table.fields), + properties: convertFieldsToProperties(table.fields) } as QueryDefinition; // Add getOne query (by ID) @@ -134,7 +133,7 @@ export function generateIntrospectionSchema( qtype: 'getOne', model: modelName, selection, - properties: convertFieldsToProperties(table.fields), + properties: convertFieldsToProperties(table.fields) } as QueryDefinition; // Add create mutation @@ -157,11 +156,11 @@ export function generateIntrospectionSchema( isNotNull: true, isArray: false, isArrayNotNull: false, - properties: convertFieldsToNestedProperties(table.fields), - }, - }, - }, - }, + properties: convertFieldsToNestedProperties(table.fields) + } + } + } + } } as MutationDefinition; // Add update mutation @@ -184,11 +183,11 @@ export function generateIntrospectionSchema( isNotNull: true, isArray: false, isArrayNotNull: false, - properties: convertFieldsToNestedProperties(table.fields), - }, - }, - }, - }, + properties: convertFieldsToNestedProperties(table.fields) + } + } + } + } } as MutationDefinition; // Add delete mutation @@ -210,11 +209,11 @@ export function generateIntrospectionSchema( type: 'UUID', isNotNull: true, isArray: false, - isArrayNotNull: false, - }, - }, - }, - }, + isArrayNotNull: false + } + } + } + } } as MutationDefinition; } @@ -233,7 +232,7 @@ function convertFieldsToProperties(fields: CleanTable['fields']) { type: field.type.gqlType, isNotNull: !field.type.gqlType.endsWith('!'), isArray: field.type.isArray, - isArrayNotNull: false, + isArrayNotNull: false }; }); @@ -252,7 +251,7 @@ function convertFieldsToNestedProperties(fields: CleanTable['fields']) { type: field.type.gqlType, isNotNull: false, // Mutations typically allow optional fields isArray: field.type.isArray, - isArrayNotNull: false, + isArrayNotNull: false }; }); @@ -268,7 +267,7 @@ export function createASTQueryBuilder(tables: CleanTable[]): QueryBuilder { return new QueryBuilder({ meta: metaObject, - introspection: introspectionSchema, + introspection: introspectionSchema }); } @@ -370,13 +369,13 @@ function generateSelectQueryAST( variableDefinitions.push( t.variableDefinition({ variable: t.variable({ name: 'first' }), - type: t.namedType({ type: 'Int' }), + type: t.namedType({ type: 'Int' }) }) ); queryArgs.push( t.argument({ name: 'first', - value: t.variable({ name: 'first' }), + value: t.variable({ name: 'first' }) }) ); } @@ -385,13 +384,13 @@ function generateSelectQueryAST( variableDefinitions.push( t.variableDefinition({ variable: t.variable({ name: 'offset' }), - type: t.namedType({ type: 'Int' }), + type: t.namedType({ type: 'Int' }) }) ); queryArgs.push( t.argument({ name: 'offset', - value: t.variable({ name: 'offset' }), + value: t.variable({ name: 'offset' }) }) ); } @@ -401,13 +400,13 @@ function generateSelectQueryAST( variableDefinitions.push( t.variableDefinition({ variable: t.variable({ name: 'after' }), - type: t.namedType({ type: 'Cursor' }), + type: t.namedType({ type: 'Cursor' }) }) ); queryArgs.push( t.argument({ name: 'after', - value: t.variable({ name: 'after' }), + value: t.variable({ name: 'after' }) }) ); } @@ -416,13 +415,13 @@ function generateSelectQueryAST( variableDefinitions.push( t.variableDefinition({ variable: t.variable({ name: 'before' }), - type: t.namedType({ type: 'Cursor' }), + type: t.namedType({ type: 'Cursor' }) }) ); queryArgs.push( t.argument({ name: 'before', - value: t.variable({ name: 'before' }), + value: t.variable({ name: 'before' }) }) ); } @@ -432,13 +431,13 @@ function generateSelectQueryAST( variableDefinitions.push( t.variableDefinition({ variable: t.variable({ name: 'filter' }), - type: t.namedType({ type: `${table.name}Filter` }), + type: t.namedType({ type: `${table.name}Filter` }) }) ); queryArgs.push( t.argument({ name: 'filter', - value: t.variable({ name: 'filter' }), + value: t.variable({ name: 'filter' }) }) ); } @@ -451,15 +450,15 @@ function generateSelectQueryAST( // PostGraphile expects [ProductsOrderBy!] - list of non-null enum values type: t.listType({ type: t.nonNullType({ - type: t.namedType({ type: toOrderByTypeName(table.name) }), - }), - }), + type: t.namedType({ type: toOrderByTypeName(table.name) }) + }) + }) }) ); queryArgs.push( t.argument({ name: 'orderBy', - value: t.variable({ name: 'orderBy' }), + value: t.variable({ name: 'orderBy' }) }) ); } @@ -470,9 +469,9 @@ function generateSelectQueryAST( t.field({ name: 'nodes', selectionSet: t.selectionSet({ - selections: fieldSelections, - }), - }), + selections: fieldSelections + }) + }) ]; // Add pageInfo if requested (for cursor-based pagination / infinite scroll) @@ -489,9 +488,9 @@ function generateSelectQueryAST( t.field({ name: 'hasNextPage' }), t.field({ name: 'hasPreviousPage' }), t.field({ name: 'startCursor' }), - t.field({ name: 'endCursor' }), - ], - }), + t.field({ name: 'endCursor' }) + ] + }) }) ); } @@ -508,13 +507,13 @@ function generateSelectQueryAST( name: pluralName, args: queryArgs, selectionSet: t.selectionSet({ - selections: connectionSelections, - }), - }), - ], - }), - }), - ], + selections: connectionSelections + }) + }) + ] + }) + }) + ] }); return print(ast); @@ -595,20 +594,20 @@ function generateFieldSelectionsFromOptions( t.argument({ name: 'first', value: t.intValue({ - value: DEFAULT_NESTED_RELATION_FIRST.toString(), - }), - }), + value: DEFAULT_NESTED_RELATION_FIRST.toString() + }) + }) ], selectionSet: t.selectionSet({ selections: [ t.field({ name: 'nodes', selectionSet: t.selectionSet({ - selections: nestedSelections, - }), - }), - ], - }), + selections: nestedSelections + }) + }) + ] + }) }) ); } else { @@ -617,8 +616,8 @@ function generateFieldSelectionsFromOptions( t.field({ name: fieldName, selectionSet: t.selectionSet({ - selections: nestedSelections, - }), + selections: nestedSelections + }) }) ); } @@ -749,9 +748,9 @@ function generateFindOneQueryAST(table: CleanTable): string { t.variableDefinition({ variable: t.variable({ name: 'id' }), type: t.nonNullType({ - type: t.namedType({ type: 'UUID' }), - }), - }), + type: t.namedType({ type: 'UUID' }) + }) + }) ], selectionSet: t.selectionSet({ selections: [ @@ -760,17 +759,17 @@ function generateFindOneQueryAST(table: CleanTable): string { args: [ t.argument({ name: 'id', - value: t.variable({ name: 'id' }), - }), + value: t.variable({ name: 'id' }) + }) ], selectionSet: t.selectionSet({ - selections: fieldSelections, - }), - }), - ], - }), - }), - ], + selections: fieldSelections + }) + }) + ] + }) + }) + ] }); return print(ast); @@ -790,8 +789,8 @@ function generateCountQueryAST(table: CleanTable): string { variableDefinitions: [ t.variableDefinition({ variable: t.variable({ name: 'filter' }), - type: t.namedType({ type: `${table.name}Filter` }), - }), + type: t.namedType({ type: `${table.name}Filter` }) + }) ], selectionSet: t.selectionSet({ selections: [ @@ -800,17 +799,17 @@ function generateCountQueryAST(table: CleanTable): string { args: [ t.argument({ name: 'filter', - value: t.variable({ name: 'filter' }), - }), + value: t.variable({ name: 'filter' }) + }) ], selectionSet: t.selectionSet({ - selections: [t.field({ name: 'totalCount' })], - }), - }), - ], - }), - }), - ], + selections: [t.field({ name: 'totalCount' })] + }) + }) + ] + }) + }) + ] }); return print(ast); diff --git a/graphql/codegen/src/index.ts b/graphql/codegen/src/index.ts index 19ae82473..9d794f364 100644 --- a/graphql/codegen/src/index.ts +++ b/graphql/codegen/src/index.ts @@ -22,22 +22,22 @@ 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 { camelizeArgv,codegenQuestions, printResult, splitCommas } from './cli/shared'; // Database schema utilities (re-exported from core for convenience) -export { - buildSchemaFromDatabase, - buildSchemaSDLFromDatabase, -} from './core/database'; export type { BuildSchemaFromDatabaseOptions, - BuildSchemaFromDatabaseResult, + 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..09e457006 100644 --- a/graphql/codegen/src/types/config.ts +++ b/graphql/codegen/src/types/config.ts @@ -356,7 +356,7 @@ export const DEFAULT_WATCH_CONFIG: WatchConfig = { pollInterval: 3000, debounce: 800, touchFile: undefined, - clearScreen: true, + clearScreen: true }; /** @@ -367,7 +367,7 @@ export const DEFAULT_QUERY_KEY_CONFIG: QueryKeyConfig = { relationships: {}, generateScopedKeys: true, generateCascadeHelpers: true, - generateMutationKeys: true, + generateMutationKeys: true }; /** @@ -380,36 +380,36 @@ export const DEFAULT_CONFIG: GraphQLSDKConfigTarget = { tables: { include: ['*'], exclude: [], - systemExclude: [], + systemExclude: [] }, queries: { include: ['*'], exclude: [], - systemExclude: ['_meta', 'query'], // Internal PostGraphile queries + systemExclude: ['_meta', 'query'] // Internal PostGraphile queries }, mutations: { include: ['*'], exclude: [], - systemExclude: [], + systemExclude: [] }, excludeFields: [], hooks: { queries: true, mutations: true, - queryKeyPrefix: 'graphql', + queryKeyPrefix: 'graphql' }, postgraphile: { - schema: 'public', + schema: 'public' }, codegen: { maxFieldDepth: 2, - skipQueryField: true, + skipQueryField: true }, orm: false, reactQuery: false, browserCompatible: true, queryKeys: DEFAULT_QUERY_KEY_CONFIG, - watch: DEFAULT_WATCH_CONFIG, + watch: DEFAULT_WATCH_CONFIG }; diff --git a/graphql/codegen/src/types/index.ts b/graphql/codegen/src/types/index.ts index 8e23aad73..83a920137 100644 --- a/graphql/codegen/src/types/index.ts +++ b/graphql/codegen/src/types/index.ts @@ -4,59 +4,58 @@ // 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, + GraphQLSDKConfigTarget } from './config'; - export { + DEFAULT_CONFIG, defineConfig, getConfigOptions, - mergeConfig, - DEFAULT_CONFIG, + mergeConfig } from './config'; From b5eb861201bca561c0604b6e3e74ee3689a25da7 Mon Sep 17 00:00:00 2001 From: yyyyaaa Date: Sat, 7 Feb 2026 14:32:30 +0700 Subject: [PATCH 02/17] feat(graphql-codegen): unify ORM and RQ selection core --- .../client-generator.test.ts.snap | 30 +- .../input-types-generator.test.ts.snap | 43 +- .../model-generator.test.ts.snap | 292 ++++-- .../__snapshots__/query-builder.test.ts.snap | 227 +++++ .../react-query-hooks.test.ts.snap | 947 ++++++++++++------ .../__tests__/codegen/query-builder.test.ts | 343 ++++++- .../src/core/codegen/custom-mutations.ts | 53 +- .../src/core/codegen/custom-queries.ts | 238 +++-- graphql/codegen/src/core/codegen/index.ts | 7 + graphql/codegen/src/core/codegen/mutations.ts | 105 +- .../core/codegen/orm/custom-ops-generator.ts | 47 +- .../core/codegen/orm/input-types-generator.ts | 115 ++- .../src/core/codegen/orm/model-generator.ts | 678 ++++++++----- .../src/core/codegen/orm/select-types.ts | 33 +- graphql/codegen/src/core/codegen/queries.ts | 248 +++-- .../src/core/codegen/select-helpers.ts | 9 +- graphql/codegen/src/core/codegen/selection.ts | 87 ++ .../core/codegen/templates/query-builder.ts | 57 +- .../core/codegen/templates/select-types.ts | 30 +- 19 files changed, 2652 insertions(+), 937 deletions(-) create mode 100644 graphql/codegen/src/__tests__/codegen/__snapshots__/query-builder.test.ts.snap create mode 100644 graphql/codegen/src/core/codegen/selection.ts 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 31e4f0863..df8457471 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 @@ -317,16 +317,10 @@ export interface DeleteArgs { /** * 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: @@ -343,15 +337,25 @@ 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 fafb3a3d1..4ed4ce22b 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 @@ -8,16 +8,25 @@ exports[`model-generator generates model with all CRUD methods 1`] = ` */ import { OrmClient } from "../client"; import { QueryBuilder, buildFindManyDocument, buildFindFirstDocument, buildFindOneDocument, buildCreateDocument, buildUpdateByPkDocument, buildDeleteByPkDocument } from "../query-builder"; -import type { ConnectionResult, FindManyArgs, FindFirstArgs, CreateArgs, UpdateArgs, DeleteArgs, InferSelectResult, DeepExact } from "../select-types"; +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"; const defaultSelect = { id: true } as const; export class UserModel { constructor(private client: OrmClient) {} - findMany(args?: FindManyArgs, UserFilter, UsersOrderBy>): QueryBuilder<{ + findMany(args: FindManyArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ users: ConnectionResult>; - }> { + }>; + findMany(args?: Omit, "select"> & { + select?: undefined; + }): QueryBuilder<{ + users: ConnectionResult>; + }>; + findMany(args?: FindManyArgs) { const { document, variables @@ -29,7 +38,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", @@ -39,17 +48,27 @@ export class UserModel { variables }); } - findFirst(args?: FindFirstArgs, UserFilter>): QueryBuilder<{ + findFirst(args: FindFirstArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ users: { nodes: InferSelectResult[]; }; - }> { + }>; + findFirst(args?: Omit, "select"> & { + select?: undefined; + }): QueryBuilder<{ + users: { + nodes: InferSelectResult[]; + }; + }>; + findFirst(args?: FindFirstArgs) { const { document, variables } = buildFindFirstDocument("User", "users", args?.select ?? defaultSelect, { where: args?.where - }, "UserFilter"); + }, "UserFilter", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "query", @@ -59,16 +78,25 @@ export class UserModel { variables }); } - findOne(args: { + findOne(args: { id: string; - select?: DeepExact; - }): QueryBuilder<{ + select: S; + } & StrictSelect): QueryBuilder<{ user: InferSelectResult | null; - }> { + }>; + findOne(args: { + id: string; + }): QueryBuilder<{ + user: InferSelectResult | null; + }>; + findOne(args: { + id: string; + select?: UserSelect; + }) { const { document, variables - } = buildFindOneDocument("User", "user", args.id, args.select ?? defaultSelect, "id", "UUID!"); + } = buildFindOneDocument("User", "user", args.id, args.select ?? defaultSelect, "id", "UUID!", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "query", @@ -78,15 +106,25 @@ export class UserModel { variables }); } - create(args: CreateArgs, CreateUserInput["user"]>): QueryBuilder<{ + create(args: CreateArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ createUser: { user: InferSelectResult; }; - }> { + }>; + create(args: Omit, "select"> & { + select?: undefined; + }): QueryBuilder<{ + createUser: { + user: InferSelectResult; + }; + }>; + create(args: CreateArgs) { const { document, variables - } = buildCreateDocument("User", "createUser", "user", args.select ?? defaultSelect, args.data, "CreateUserInput"); + } = buildCreateDocument("User", "createUser", "user", args.select ?? defaultSelect, args.data, "CreateUserInput", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -96,17 +134,31 @@ export class UserModel { variables }); } - update(args: UpdateArgs, { + update(args: UpdateArgs): QueryBuilder<{ + }, UserPatch> & { + select: S; + } & StrictSelect): QueryBuilder<{ updateUser: { user: InferSelectResult; }; - }> { + }>; + update(args: Omit, "select"> & { + select?: undefined; + }): QueryBuilder<{ + updateUser: { + user: InferSelectResult; + }; + }>; + update(args: UpdateArgs) { const { document, variables - } = buildUpdateByPkDocument("User", "updateUser", "user", args.select ?? defaultSelect, args.where.id, args.data, "UpdateUserInput", "id"); + } = buildUpdateByPkDocument("User", "updateUser", "user", args.select ?? defaultSelect, args.where.id, args.data, "UpdateUserInput", "id", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -116,17 +168,31 @@ export class UserModel { variables }); } - delete(args: DeleteArgs<{ + delete(args: DeleteArgs<{ id: string; - }, DeepExact>): QueryBuilder<{ + }, S> & { + select: S; + } & StrictSelect): QueryBuilder<{ deleteUser: { user: InferSelectResult; }; - }> { + }>; + delete(args: Omit, "select"> & { + select?: undefined; + }): QueryBuilder<{ + deleteUser: { + user: InferSelectResult; + }; + }>; + delete(args: DeleteArgs<{ + id: string; + }, UserSelect>) { const { document, variables - } = buildDeleteByPkDocument("User", "deleteUser", "user", args.where.id, "DeleteUserInput", "id", args.select ?? defaultSelect); + } = buildDeleteByPkDocument("User", "deleteUser", "user", args.where.id, "DeleteUserInput", "id", args.select ?? defaultSelect, connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -147,16 +213,25 @@ exports[`model-generator generates model without update/delete when not availabl */ import { OrmClient } from "../client"; import { QueryBuilder, buildFindManyDocument, buildFindFirstDocument, buildFindOneDocument, buildCreateDocument, buildUpdateByPkDocument, buildDeleteByPkDocument } from "../query-builder"; -import type { ConnectionResult, FindManyArgs, FindFirstArgs, CreateArgs, UpdateArgs, DeleteArgs, InferSelectResult, DeepExact } from "../select-types"; +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"; const defaultSelect = { id: true } as const; export class AuditLogModel { constructor(private client: OrmClient) {} - findMany(args?: FindManyArgs, AuditLogFilter, AuditLogsOrderBy>): QueryBuilder<{ + findMany(args: FindManyArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ auditLogs: ConnectionResult>; - }> { + }>; + findMany(args?: Omit, "select"> & { + select?: undefined; + }): QueryBuilder<{ + auditLogs: ConnectionResult>; + }>; + findMany(args?: FindManyArgs) { const { document, variables @@ -168,7 +243,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", @@ -178,17 +253,27 @@ export class AuditLogModel { variables }); } - findFirst(args?: FindFirstArgs, AuditLogFilter>): QueryBuilder<{ + findFirst(args: FindFirstArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ auditLogs: { nodes: InferSelectResult[]; }; - }> { + }>; + findFirst(args?: Omit, "select"> & { + select?: undefined; + }): QueryBuilder<{ + auditLogs: { + nodes: InferSelectResult[]; + }; + }>; + findFirst(args?: FindFirstArgs) { const { document, variables } = buildFindFirstDocument("AuditLog", "auditLogs", args?.select ?? defaultSelect, { where: args?.where - }, "AuditLogFilter"); + }, "AuditLogFilter", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "query", @@ -198,16 +283,25 @@ export class AuditLogModel { variables }); } - findOne(args: { + findOne(args: { id: string; - select?: DeepExact; - }): QueryBuilder<{ + select: S; + } & StrictSelect): QueryBuilder<{ auditLog: InferSelectResult | null; - }> { + }>; + findOne(args: { + id: string; + }): QueryBuilder<{ + auditLog: InferSelectResult | null; + }>; + findOne(args: { + id: string; + select?: AuditLogSelect; + }) { const { document, variables - } = buildFindOneDocument("AuditLog", "auditLog", args.id, args.select ?? defaultSelect, "id", "UUID!"); + } = buildFindOneDocument("AuditLog", "auditLog", args.id, args.select ?? defaultSelect, "id", "UUID!", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "query", @@ -217,15 +311,25 @@ export class AuditLogModel { variables }); } - create(args: CreateArgs, CreateAuditLogInput["auditLog"]>): QueryBuilder<{ + create(args: CreateArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ createAuditLog: { auditLog: InferSelectResult; }; - }> { + }>; + create(args: Omit, "select"> & { + select?: undefined; + }): QueryBuilder<{ + createAuditLog: { + auditLog: InferSelectResult; + }; + }>; + create(args: CreateArgs) { const { document, variables - } = buildCreateDocument("AuditLog", "createAuditLog", "auditLog", args.select ?? defaultSelect, args.data, "CreateAuditLogInput"); + } = buildCreateDocument("AuditLog", "createAuditLog", "auditLog", args.select ?? defaultSelect, args.data, "CreateAuditLogInput", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -246,16 +350,25 @@ exports[`model-generator handles custom query/mutation names 1`] = ` */ import { OrmClient } from "../client"; import { QueryBuilder, buildFindManyDocument, buildFindFirstDocument, buildFindOneDocument, buildCreateDocument, buildUpdateByPkDocument, buildDeleteByPkDocument } from "../query-builder"; -import type { ConnectionResult, FindManyArgs, FindFirstArgs, CreateArgs, UpdateArgs, DeleteArgs, InferSelectResult, DeepExact } from "../select-types"; +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"; const defaultSelect = { id: true } as const; export class OrganizationModel { constructor(private client: OrmClient) {} - findMany(args?: FindManyArgs, OrganizationFilter, OrganizationsOrderBy>): QueryBuilder<{ + findMany(args: FindManyArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ allOrganizations: ConnectionResult>; - }> { + }>; + findMany(args?: Omit, "select"> & { + select?: undefined; + }): QueryBuilder<{ + allOrganizations: ConnectionResult>; + }>; + findMany(args?: FindManyArgs) { const { document, variables @@ -267,7 +380,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", @@ -277,17 +390,27 @@ export class OrganizationModel { variables }); } - findFirst(args?: FindFirstArgs, OrganizationFilter>): QueryBuilder<{ + findFirst(args: FindFirstArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ allOrganizations: { nodes: InferSelectResult[]; }; - }> { + }>; + findFirst(args?: Omit, "select"> & { + select?: undefined; + }): QueryBuilder<{ + allOrganizations: { + nodes: InferSelectResult[]; + }; + }>; + findFirst(args?: FindFirstArgs) { const { document, variables } = buildFindFirstDocument("Organization", "allOrganizations", args?.select ?? defaultSelect, { where: args?.where - }, "OrganizationFilter"); + }, "OrganizationFilter", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "query", @@ -297,16 +420,25 @@ export class OrganizationModel { variables }); } - findOne(args: { + findOne(args: { id: string; - select?: DeepExact; - }): QueryBuilder<{ + select: S; + } & StrictSelect): QueryBuilder<{ organizationById: InferSelectResult | null; - }> { + }>; + findOne(args: { + id: string; + }): QueryBuilder<{ + organizationById: InferSelectResult | null; + }>; + findOne(args: { + id: string; + select?: OrganizationSelect; + }) { const { document, variables - } = buildFindOneDocument("Organization", "organizationById", args.id, args.select ?? defaultSelect, "id", "UUID!"); + } = buildFindOneDocument("Organization", "organizationById", args.id, args.select ?? defaultSelect, "id", "UUID!", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "query", @@ -316,15 +448,25 @@ export class OrganizationModel { variables }); } - create(args: CreateArgs, CreateOrganizationInput["organization"]>): QueryBuilder<{ + create(args: CreateArgs & { + select: S; + } & StrictSelect): QueryBuilder<{ registerOrganization: { organization: InferSelectResult; }; - }> { + }>; + create(args: Omit, "select"> & { + select?: undefined; + }): QueryBuilder<{ + registerOrganization: { + organization: InferSelectResult; + }; + }>; + create(args: CreateArgs) { const { document, variables - } = buildCreateDocument("Organization", "registerOrganization", "organization", args.select ?? defaultSelect, args.data, "CreateOrganizationInput"); + } = buildCreateDocument("Organization", "registerOrganization", "organization", args.select ?? defaultSelect, args.data, "CreateOrganizationInput", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -334,17 +476,31 @@ export class OrganizationModel { variables }); } - update(args: UpdateArgs, { + update(args: UpdateArgs): QueryBuilder<{ + }, OrganizationPatch> & { + select: S; + } & StrictSelect): QueryBuilder<{ modifyOrganization: { organization: InferSelectResult; }; - }> { + }>; + update(args: Omit, "select"> & { + select?: undefined; + }): QueryBuilder<{ + modifyOrganization: { + organization: InferSelectResult; + }; + }>; + update(args: UpdateArgs) { const { document, variables - } = buildUpdateByPkDocument("Organization", "modifyOrganization", "organization", args.select ?? defaultSelect, args.where.id, args.data, "UpdateOrganizationInput", "id"); + } = buildUpdateByPkDocument("Organization", "modifyOrganization", "organization", args.select ?? defaultSelect, args.where.id, args.data, "UpdateOrganizationInput", "id", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -354,17 +510,31 @@ export class OrganizationModel { variables }); } - delete(args: DeleteArgs<{ + delete(args: DeleteArgs<{ id: string; - }, DeepExact>): QueryBuilder<{ + }, S> & { + select: S; + } & StrictSelect): QueryBuilder<{ removeOrganization: { organization: InferSelectResult; }; - }> { + }>; + delete(args: Omit, "select"> & { + select?: undefined; + }): QueryBuilder<{ + removeOrganization: { + organization: InferSelectResult; + }; + }>; + delete(args: DeleteArgs<{ + id: string; + }, OrganizationSelect>) { const { document, variables - } = buildDeleteByPkDocument("Organization", "removeOrganization", "organization", args.where.id, "DeleteOrganizationInput", "id", args.select ?? defaultSelect); + } = buildDeleteByPkDocument("Organization", "removeOrganization", "organization", args.where.id, "DeleteOrganizationInput", "id", args.select ?? defaultSelect, 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 1e1d1710d..9ccd55d96 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 @@ -188,26 +188,36 @@ exports[`Custom Mutation Hook Generators generateCustomMutationHook generates cu */ import { useMutation } from '@tanstack/react-query'; -import type { UseMutationOptions } from '@tanstack/react-query'; +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'; import type { LoginVariables } from '../../orm/mutation'; import type { LoginPayloadSelect, LoginPayload } from '../../orm/input-types'; -import type { DeepExact, InferSelectResult } from '../../orm/select-types'; +import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; export type { LoginVariables } from '../../orm/mutation'; export type { LoginPayloadSelect } from '../../orm/input-types'; const defaultSelect = { token: true } as const; -export function useLoginMutation( - args?: { select?: DeepExact }, - options?: Omit }, Error, LoginVariables>, 'mutationFn'> +export function useLoginMutation( + params: { selection: ({ fields: S } & StrictSelect) } & Omit }, Error, LoginVariables>, 'mutationFn'> +): UseMutationResult<{ login: InferSelectResult }, Error, LoginVariables>; +export function useLoginMutation( + params?: { selection?: ({ fields?: undefined }) } & 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: LoginVariables) => getClient().mutation.login(variables, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), - ...options, + mutationFn: (variables: LoginVariables) => getClient().mutation.login(variables, { select: (args?.select ?? defaultSelect) as LoginPayloadSelect }).unwrap(), + ...mutationOptions, }); } " @@ -221,26 +231,36 @@ exports[`Custom Mutation Hook Generators generateCustomMutationHook generates cu */ import { useMutation } from '@tanstack/react-query'; -import type { UseMutationOptions } from '@tanstack/react-query'; +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'; import type { RegisterVariables } from '../../orm/mutation'; import type { RegisterPayloadSelect, RegisterPayload } from '../../orm/input-types'; -import type { DeepExact, InferSelectResult } from '../../orm/select-types'; +import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; export type { RegisterVariables } from '../../orm/mutation'; export type { RegisterPayloadSelect } from '../../orm/input-types'; const defaultSelect = { token: true } as const; -export function useRegisterMutation( - args?: { select?: DeepExact }, - options?: Omit }, Error, RegisterVariables>, 'mutationFn'> +export function useRegisterMutation( + params: { selection: ({ fields: S } & StrictSelect) } & Omit }, Error, RegisterVariables>, 'mutationFn'> +): UseMutationResult<{ register: InferSelectResult }, Error, RegisterVariables>; +export function useRegisterMutation( + params?: { selection?: ({ fields?: undefined }) } & 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: RegisterVariables) => getClient().mutation.register(variables, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), - ...options, + mutationFn: (variables: RegisterVariables) => getClient().mutation.register(variables, { select: (args?.select ?? defaultSelect) as RegisterPayloadSelect }).unwrap(), + ...mutationOptions, }); } " @@ -254,24 +274,34 @@ exports[`Custom Mutation Hook Generators generateCustomMutationHook generates cu */ import { useMutation } from '@tanstack/react-query'; -import type { UseMutationOptions } from '@tanstack/react-query'; +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'; import type { LogoutPayloadSelect, LogoutPayload } from '../../orm/input-types'; -import type { DeepExact, InferSelectResult } from '../../orm/select-types'; +import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; export type { LogoutPayloadSelect } from '../../orm/input-types'; const defaultSelect = { success: true } as const; -export function useLogoutMutation( - args?: { select?: DeepExact }, - options?: Omit }, Error, void>, 'mutationFn'> +export function useLogoutMutation( + params: { selection: ({ fields: S } & StrictSelect) } & Omit }, Error, void>, 'mutationFn'> +): UseMutationResult<{ logout: InferSelectResult }, Error, void>; +export function useLogoutMutation( + params?: { selection?: ({ fields?: undefined }) } & 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: () => getClient().mutation.logout({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), - ...options, + mutationFn: () => getClient().mutation.logout({ select: (args?.select ?? defaultSelect) as LogoutPayloadSelect }).unwrap(), + ...mutationOptions, }); } " @@ -285,24 +315,34 @@ exports[`Custom Mutation Hook Generators generateCustomMutationHook generates cu */ import { useMutation } from '@tanstack/react-query'; -import type { UseMutationOptions } from '@tanstack/react-query'; +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 { DeepExact, InferSelectResult } from '../../orm/select-types'; +import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; export type { LoginVariables } from '../../orm/mutation'; export type { LoginPayloadSelect } from '../../orm/input-types'; const defaultSelect = { token: true } as const; -export function useLoginMutation( - args?: { select?: DeepExact }, - options?: Omit }, Error, LoginVariables>, 'mutationFn'> +export function useLoginMutation( + params: { selection: ({ fields: S } & StrictSelect) } & Omit }, Error, LoginVariables>, 'mutationFn'> +): UseMutationResult<{ login: InferSelectResult }, Error, LoginVariables>; +export function useLoginMutation( + params?: { selection?: ({ fields?: undefined }) } & 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: LoginVariables) => getClient().mutation.login(variables, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), - ...options, + mutationFn: (variables: LoginVariables) => getClient().mutation.login(variables, { select: (args?.select ?? defaultSelect) as LoginPayloadSelect }).unwrap(), + ...mutationOptions, }); } " @@ -316,12 +356,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 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'; import type { SearchUsersVariables } from '../../orm/query'; import type { UserSelect, User } from '../../orm/input-types'; -import type { DeepExact, InferSelectResult } from '../../orm/select-types'; +import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; export type { SearchUsersVariables } from '../../orm/query'; export type { UserSelect } from '../../orm/input-types'; @@ -343,16 +385,25 @@ export const searchUsersQueryKey = customQueryKeys.searchUsers; * } * \`\`\` */ -export function useSearchUsersQuery( - variables: SearchUsersVariables, - args?: { select?: DeepExact }, - options?: Omit[] }, Error>, '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?: ({ fields?: undefined }) } & 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: () => getClient().query.searchUsers(variables!, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), - enabled: !!variables && options?.enabled !== false, - ...options, + queryFn: () => getClient().query.searchUsers(variables!, { select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + enabled: !!variables && params?.enabled !== false, + ...queryOptions, }); } @@ -364,11 +415,18 @@ export function useSearchUsersQuery( - variables: SearchUsersVariables, - args?: { select?: DeepExact } +export async function fetchSearchUsersQuery( + params: { variables: SearchUsersVariables; selection: ({ fields: S } & StrictSelect) } +): Promise<{ searchUsers: InferSelectResult[] }>; +export async function fetchSearchUsersQuery( + params: { variables: SearchUsersVariables; selection?: ({ fields?: undefined }) } +): Promise<{ searchUsers: InferSelectResult[] }>; +export async function fetchSearchUsersQuery( + params: { variables: SearchUsersVariables; selection?: SelectionConfig }, ) { - return getClient().query.searchUsers(variables!, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(); + const variables = params?.variables; + const args = buildSelectionArgs(params?.selection); + return getClient().query.searchUsers(variables!, { select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(); } /** @@ -379,14 +437,23 @@ export async function fetchSearchUsersQuery( +export async function prefetchSearchUsersQuery( + queryClient: QueryClient, + params: { variables: SearchUsersVariables; selection: ({ fields: S } & StrictSelect) } +): Promise; +export async function prefetchSearchUsersQuery( + queryClient: QueryClient, + params: { variables: SearchUsersVariables; selection?: ({ fields?: undefined }) } +): Promise; +export async function prefetchSearchUsersQuery( queryClient: QueryClient, - variables: SearchUsersVariables, - args?: { select?: DeepExact } + params: { variables: SearchUsersVariables; selection?: SelectionConfig } ): Promise { + const variables = params?.variables; + const args = buildSelectionArgs(params?.selection); await queryClient.prefetchQuery({ queryKey: searchUsersQueryKey(variables), - queryFn: () => getClient().query.searchUsers(variables!, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + queryFn: () => getClient().query.searchUsers(variables!, { select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), }); } " @@ -400,11 +467,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 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'; import type { UserSelect, User } from '../../orm/input-types'; -import type { DeepExact, InferSelectResult } from '../../orm/select-types'; +import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; export type { UserSelect } from '../../orm/input-types'; @@ -425,14 +494,22 @@ export const currentUserQueryKey = customQueryKeys.currentUser; * } * \`\`\` */ -export function useCurrentUserQuery( - args?: { select?: DeepExact }, - options?: Omit }, Error>, 'queryKey' | 'queryFn'> +export function useCurrentUserQuery }>( + params: { selection: ({ fields: S } & StrictSelect) } & Omit }, Error, TData>, 'queryKey' | 'queryFn'> +): UseQueryResult; +export function useCurrentUserQuery }>( + params?: { selection?: ({ fields?: undefined }) } & 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: () => getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), - ...options, + queryFn: () => getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + ...queryOptions, }); } @@ -444,10 +521,17 @@ export function useCurrentUserQuery( - args?: { select?: DeepExact } +export async function fetchCurrentUserQuery( + params: { selection: ({ fields: S } & StrictSelect) } +): Promise<{ currentUser: InferSelectResult }>; +export async function fetchCurrentUserQuery( + params?: { selection?: ({ fields?: undefined }) }, +): Promise<{ currentUser: InferSelectResult }>; +export async function fetchCurrentUserQuery( + params?: { selection?: SelectionConfig }, ) { - return getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(); + const args = buildSelectionArgs(params?.selection); + return getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(); } /** @@ -458,13 +542,22 @@ export async function fetchCurrentUserQuery( +export async function prefetchCurrentUserQuery( + queryClient: QueryClient, + params: { selection: ({ fields: S } & StrictSelect) } +): Promise; +export async function prefetchCurrentUserQuery( queryClient: QueryClient, - args?: { select?: DeepExact } + params?: { selection?: ({ fields?: undefined }) } +): Promise; +export async function prefetchCurrentUserQuery( + queryClient: QueryClient, + params?: { selection?: SelectionConfig } ): Promise { + const args = buildSelectionArgs(params?.selection); await queryClient.prefetchQuery({ queryKey: currentUserQueryKey(), - queryFn: () => getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + queryFn: () => getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), }); } " @@ -478,10 +571,12 @@ exports[`Custom Query Hook Generators generateCustomQueryHook generates custom q */ import { useQuery } from '@tanstack/react-query'; -import type { UseQueryOptions, QueryClient } from '@tanstack/react-query'; +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 { DeepExact, InferSelectResult } from '../../orm/select-types'; +import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; export type { UserSelect } from '../../orm/input-types'; @@ -502,14 +597,22 @@ export const currentUserQueryKey = () => ['currentUser'] as const; * } * \`\`\` */ -export function useCurrentUserQuery( - args?: { select?: DeepExact }, - options?: Omit }, Error>, 'queryKey' | 'queryFn'> +export function useCurrentUserQuery }>( + params: { selection: ({ fields: S } & StrictSelect) } & Omit }, Error, TData>, 'queryKey' | 'queryFn'> +): UseQueryResult; +export function useCurrentUserQuery }>( + params?: { selection?: ({ fields?: undefined }) } & 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: () => getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), - ...options, + queryFn: () => getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + ...queryOptions, }); } @@ -521,10 +624,17 @@ export function useCurrentUserQuery( - args?: { select?: DeepExact } +export async function fetchCurrentUserQuery( + params: { selection: ({ fields: S } & StrictSelect) } +): Promise<{ currentUser: InferSelectResult }>; +export async function fetchCurrentUserQuery( + params?: { selection?: ({ fields?: undefined }) }, +): Promise<{ currentUser: InferSelectResult }>; +export async function fetchCurrentUserQuery( + params?: { selection?: SelectionConfig }, ) { - return getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(); + const args = buildSelectionArgs(params?.selection); + return getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(); } /** @@ -535,13 +645,22 @@ export async function fetchCurrentUserQuery( +export async function prefetchCurrentUserQuery( + queryClient: QueryClient, + params: { selection: ({ fields: S } & StrictSelect) } +): Promise; +export async function prefetchCurrentUserQuery( + queryClient: QueryClient, + params?: { selection?: ({ fields?: undefined }) } +): Promise; +export async function prefetchCurrentUserQuery( queryClient: QueryClient, - args?: { select?: DeepExact } + params?: { selection?: SelectionConfig } ): Promise { + const args = buildSelectionArgs(params?.selection); await queryClient.prefetchQuery({ queryKey: currentUserQueryKey(), - queryFn: () => getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + queryFn: () => getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), }); } " @@ -555,8 +674,10 @@ exports[`Mutation Hook Generators generateCreateMutationHook generates create mu */ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import type { UseMutationOptions } from '@tanstack/react-query'; +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'; import type { @@ -564,10 +685,7 @@ import type { UserWithRelations, CreateUserInput, } from '../../orm/input-types'; -import type { - DeepExact, - InferSelectResult, -} from '../../orm/select-types'; +import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; export type { UserSelect, UserWithRelations, CreateUserInput } from '../../orm/input-types'; @@ -579,24 +697,32 @@ const defaultSelect = { id: true } as const; * @example * \`\`\`tsx * const { mutate, isPending } = useCreateUserMutation({ - * select: { id: true, name: true }, + * selection: { fields: { id: true, name: true } }, * }); * * mutate({ name: 'New item' }); * \`\`\` */ -export function useCreateUserMutation( - args?: { select?: DeepExact }, - options?: Omit } }, Error, CreateUserInput['user']>, '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?: ({ fields?: undefined }) } & 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: (data: CreateUserInput['user']) => getClient().user.create({ data, select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + mutationFn: (data: CreateUserInput['user']) => getClient().user.create({ data, select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), onSuccess: () => { queryClient.invalidateQueries({ queryKey: userKeys.lists() }); }, - ...options, + ...mutationOptions, }); } " @@ -610,8 +736,10 @@ exports[`Mutation Hook Generators generateCreateMutationHook generates create mu */ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import type { UseMutationOptions } from '@tanstack/react-query'; +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 { postMutationKeys } from '../mutation-keys'; import type { @@ -619,10 +747,7 @@ import type { PostWithRelations, CreatePostInput, } from '../../orm/input-types'; -import type { - DeepExact, - InferSelectResult, -} from '../../orm/select-types'; +import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; export type { PostSelect, PostWithRelations, CreatePostInput } from '../../orm/input-types'; @@ -634,24 +759,32 @@ const defaultSelect = { id: true } as const; * @example * \`\`\`tsx * const { mutate, isPending } = useCreatePostMutation({ - * select: { id: true, name: true }, + * selection: { fields: { id: true, name: true } }, * }); * * mutate({ name: 'New item' }); * \`\`\` */ -export function useCreatePostMutation( - args?: { select?: DeepExact }, - options?: Omit } }, Error, CreatePostInput['post']>, '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?: ({ fields?: undefined }) } & 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: (data: CreatePostInput['post']) => getClient().post.create({ data, select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + mutationFn: (data: CreatePostInput['post']) => getClient().post.create({ data, select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(), onSuccess: () => { queryClient.invalidateQueries({ queryKey: postKeys.lists() }); }, - ...options, + ...mutationOptions, }); } " @@ -665,17 +798,16 @@ exports[`Mutation Hook Generators generateCreateMutationHook generates create mu */ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import type { UseMutationOptions } from '@tanstack/react-query'; +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 { - DeepExact, - InferSelectResult, -} from '../../orm/select-types'; +import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; export type { UserSelect, UserWithRelations, CreateUserInput } from '../../orm/input-types'; @@ -687,23 +819,31 @@ const defaultSelect = { id: true } as const; * @example * \`\`\`tsx * const { mutate, isPending } = useCreateUserMutation({ - * select: { id: true, name: true }, + * selection: { fields: { id: true, name: true } }, * }); * * mutate({ name: 'New item' }); * \`\`\` */ -export function useCreateUserMutation( - args?: { select?: DeepExact }, - options?: Omit } }, Error, CreateUserInput['user']>, '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?: ({ fields?: undefined }) } & 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: (data: CreateUserInput['user']) => getClient().user.create({ data, select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + mutationFn: (data: CreateUserInput['user']) => getClient().user.create({ data, select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['user', 'list'] }); }, - ...options, + ...mutationOptions, }); } " @@ -717,18 +857,17 @@ exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mu */ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import type { UseMutationOptions } from '@tanstack/react-query'; +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'; import type { UserSelect, UserWithRelations, } from '../../orm/input-types'; -import type { - DeepExact, - InferSelectResult, -} from '../../orm/select-types'; +import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; export type { UserSelect, UserWithRelations } from '../../orm/input-types'; @@ -740,25 +879,33 @@ const defaultSelect = { id: true } as const; * @example * \`\`\`tsx * const { mutate, isPending } = useDeleteUserMutation({ - * select: { id: true }, + * selection: { fields: { id: true } }, * }); * * mutate({ id: 'value-to-delete' }); * \`\`\` */ -export function useDeleteUserMutation( - args?: { select?: DeepExact }, - options?: Omit } }, Error, { id: string }>, '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?: ({ fields?: undefined }) } & 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: ({ id }: { id: string }) => getClient().user.delete({ where: { id }, select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + mutationFn: ({ id }: { id: string }) => getClient().user.delete({ where: { id }, select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), onSuccess: (_, variables) => { queryClient.removeQueries({ queryKey: userKeys.detail(variables.id) }); queryClient.invalidateQueries({ queryKey: userKeys.lists() }); }, - ...options, + ...mutationOptions, }); } " @@ -772,18 +919,17 @@ exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mu */ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import type { UseMutationOptions } from '@tanstack/react-query'; +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 { postMutationKeys } from '../mutation-keys'; import type { PostSelect, PostWithRelations, } from '../../orm/input-types'; -import type { - DeepExact, - InferSelectResult, -} from '../../orm/select-types'; +import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; export type { PostSelect, PostWithRelations } from '../../orm/input-types'; @@ -795,25 +941,33 @@ const defaultSelect = { id: true } as const; * @example * \`\`\`tsx * const { mutate, isPending } = useDeletePostMutation({ - * select: { id: true }, + * selection: { fields: { id: true } }, * }); * * mutate({ id: 'value-to-delete' }); * \`\`\` */ -export function useDeletePostMutation( - args?: { select?: DeepExact }, - options?: Omit } }, Error, { id: string }>, '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?: ({ fields?: undefined }) } & 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: ({ id }: { id: string }) => getClient().post.delete({ where: { id }, select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + mutationFn: ({ id }: { id: string }) => getClient().post.delete({ where: { id }, select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(), onSuccess: (_, variables) => { queryClient.removeQueries({ queryKey: postKeys.detail(variables.id) }); queryClient.invalidateQueries({ queryKey: postKeys.lists() }); }, - ...options, + ...mutationOptions, }); } " @@ -827,16 +981,15 @@ exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mu */ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import type { UseMutationOptions } from '@tanstack/react-query'; +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 { - DeepExact, - InferSelectResult, -} from '../../orm/select-types'; +import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; export type { UserSelect, UserWithRelations } from '../../orm/input-types'; @@ -848,24 +1001,32 @@ const defaultSelect = { id: true } as const; * @example * \`\`\`tsx * const { mutate, isPending } = useDeleteUserMutation({ - * select: { id: true }, + * selection: { fields: { id: true } }, * }); * * mutate({ id: 'value-to-delete' }); * \`\`\` */ -export function useDeleteUserMutation( - args?: { select?: DeepExact }, - options?: Omit } }, Error, { id: string }>, '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?: ({ fields?: undefined }) } & 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: ({ id }: { id: string }) => getClient().user.delete({ where: { id }, select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + mutationFn: ({ id }: { id: string }) => getClient().user.delete({ where: { id }, select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), onSuccess: (_, variables) => { queryClient.removeQueries({ queryKey: ['user', 'detail', variables.id] }); queryClient.invalidateQueries({ queryKey: ['user', 'list'] }); }, - ...options, + ...mutationOptions, }); } " @@ -879,8 +1040,10 @@ exports[`Mutation Hook Generators generateUpdateMutationHook generates update mu */ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import type { UseMutationOptions } from '@tanstack/react-query'; +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'; import type { @@ -888,10 +1051,7 @@ import type { UserWithRelations, UserPatch, } from '../../orm/input-types'; -import type { - DeepExact, - InferSelectResult, -} from '../../orm/select-types'; +import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; export type { UserSelect, UserWithRelations, UserPatch } from '../../orm/input-types'; @@ -903,25 +1063,33 @@ const defaultSelect = { id: true } as const; * @example * \`\`\`tsx * const { mutate, isPending } = useUpdateUserMutation({ - * select: { id: true, name: true }, + * selection: { fields: { id: true, name: true } }, * }); * * mutate({ id: 'value-here', patch: { name: 'Updated' } }); * \`\`\` */ -export function useUpdateUserMutation( - args?: { select?: DeepExact }, - options?: Omit } }, Error, { id: string; patch: UserPatch }>, '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?: ({ fields?: undefined }) } & 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: ({ id, patch }: { id: string; patch: UserPatch }) => getClient().user.update({ where: { id }, data: patch, select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + mutationFn: ({ id, patch }: { id: string; patch: UserPatch }) => getClient().user.update({ where: { id }, data: patch, select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: userKeys.detail(variables.id) }); queryClient.invalidateQueries({ queryKey: userKeys.lists() }); }, - ...options, + ...mutationOptions, }); } " @@ -935,8 +1103,10 @@ exports[`Mutation Hook Generators generateUpdateMutationHook generates update mu */ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import type { UseMutationOptions } from '@tanstack/react-query'; +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 { postMutationKeys } from '../mutation-keys'; import type { @@ -944,10 +1114,7 @@ import type { PostWithRelations, PostPatch, } from '../../orm/input-types'; -import type { - DeepExact, - InferSelectResult, -} from '../../orm/select-types'; +import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; export type { PostSelect, PostWithRelations, PostPatch } from '../../orm/input-types'; @@ -959,25 +1126,33 @@ const defaultSelect = { id: true } as const; * @example * \`\`\`tsx * const { mutate, isPending } = useUpdatePostMutation({ - * select: { id: true, name: true }, + * selection: { fields: { id: true, name: true } }, * }); * * mutate({ id: 'value-here', patch: { name: 'Updated' } }); * \`\`\` */ -export function useUpdatePostMutation( - args?: { select?: DeepExact }, - options?: Omit } }, Error, { id: string; patch: PostPatch }>, '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?: ({ fields?: undefined }) } & 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: ({ id, patch }: { id: string; patch: PostPatch }) => getClient().post.update({ where: { id }, data: patch, select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + mutationFn: ({ id, patch }: { id: string; patch: PostPatch }) => getClient().post.update({ where: { id }, data: patch, select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(), onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: postKeys.detail(variables.id) }); queryClient.invalidateQueries({ queryKey: postKeys.lists() }); }, - ...options, + ...mutationOptions, }); } " @@ -991,17 +1166,16 @@ exports[`Mutation Hook Generators generateUpdateMutationHook generates update mu */ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import type { UseMutationOptions } from '@tanstack/react-query'; +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 { - DeepExact, - InferSelectResult, -} from '../../orm/select-types'; +import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; export type { UserSelect, UserWithRelations, UserPatch } from '../../orm/input-types'; @@ -1013,24 +1187,32 @@ const defaultSelect = { id: true } as const; * @example * \`\`\`tsx * const { mutate, isPending } = useUpdateUserMutation({ - * select: { id: true, name: true }, + * selection: { fields: { id: true, name: true } }, * }); * * mutate({ id: 'value-here', patch: { name: 'Updated' } }); * \`\`\` */ -export function useUpdateUserMutation( - args?: { select?: DeepExact }, - options?: Omit } }, Error, { id: string; patch: UserPatch }>, '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?: ({ fields?: undefined }) } & 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: ({ id, patch }: { id: string; patch: UserPatch }) => getClient().user.update({ where: { id }, data: patch, select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(), + mutationFn: ({ id, patch }: { id: string; patch: UserPatch }) => getClient().user.update({ where: { id }, data: patch, select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: ['user', 'detail', variables.id] }); queryClient.invalidateQueries({ queryKey: ['user', 'list'] }); }, - ...options, + ...mutationOptions, }); } " @@ -1044,8 +1226,10 @@ 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 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'; import type { UserSelect, @@ -1055,9 +1239,9 @@ import type { } from '../../orm/input-types'; import type { FindManyArgs, - DeepExact, InferSelectResult, ConnectionResult, + StrictSelect, } from '../../orm/select-types'; export type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy } from '../../orm/input-types'; @@ -1073,21 +1257,32 @@ export const usersQueryKey = userKeys.list; * @example * \`\`\`tsx * const { data, isLoading } = useUsersQuery({ - * select: { id: true, name: true }, - * first: 10, - * where: { 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( - args?: FindManyArgs, UserFilter, UsersOrderBy>, - options?: Omit> }, Error>, 'queryKey' | 'queryFn'> +export function useUsersQuery> }>( + params: { selection: ({ fields: S } & Omit, 'fields'> & StrictSelect) } & Omit> }, Error, TData>, 'queryKey' | 'queryFn'> +): UseQueryResult; +export function useUsersQuery> }>( + params?: { selection?: (Omit, 'fields'> & { fields?: undefined }) } & Omit> }, Error, TData>, 'queryKey' | 'queryFn'> +): UseQueryResult; +export function useUsersQuery( + params?: { selection?: ListSelectionConfig } & Omit, 'queryKey' | 'queryFn'> ) { + const selection = params?.selection; + const args = buildListSelectionArgs(selection); + const { selection: _selection, ...queryOptions } = params ?? {}; + void _selection; return useQuery({ queryKey: userKeys.list(args), - queryFn: () => getClient().user.findMany(args).unwrap(), - ...options, + queryFn: () => getClient().user.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + ...queryOptions, }); } @@ -1096,13 +1291,25 @@ export function useUsersQuery * * @example * \`\`\`ts - * const data = await fetchUsersQuery({ first: 10, select: { id: true } }); + * const data = await fetchUsersQuery({ + * selection: { + * fields: { id: true }, + * first: 10, + * }, + * }); * \`\`\` */ -export async function fetchUsersQuery( - args?: FindManyArgs, UserFilter, UsersOrderBy>, +export async function fetchUsersQuery( + params: { selection: ({ fields: S } & Omit, 'fields'> & StrictSelect) } +): Promise<{ users: ConnectionResult> }>; +export async function fetchUsersQuery( + params?: { selection?: (Omit, 'fields'> & { fields?: undefined }) } +): Promise<{ users: ConnectionResult> }>; +export async function fetchUsersQuery( + params?: { selection?: ListSelectionConfig } ) { - return getClient().user.findMany(args).unwrap(); + const args = buildListSelectionArgs(params?.selection); + return getClient().user.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(); } /** @@ -1110,16 +1317,25 @@ export async function fetchUsersQuery( +export async function prefetchUsersQuery( + queryClient: QueryClient, + params: { selection: ({ fields: S } & Omit, 'fields'> & StrictSelect) } +): Promise; +export async function prefetchUsersQuery( queryClient: QueryClient, - args?: FindManyArgs, UserFilter, UsersOrderBy>, + params?: { selection?: (Omit, 'fields'> & { fields?: undefined }) } +): Promise; +export async function prefetchUsersQuery( + queryClient: QueryClient, + params?: { selection?: ListSelectionConfig } ): Promise { + const args = buildListSelectionArgs(params?.selection); await queryClient.prefetchQuery({ queryKey: userKeys.list(args), - queryFn: () => getClient().user.findMany(args).unwrap(), + queryFn: () => getClient().user.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), }); } " @@ -1133,8 +1349,10 @@ 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 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'; import type { @@ -1145,9 +1363,9 @@ import type { } from '../../orm/input-types'; import type { FindManyArgs, - DeepExact, InferSelectResult, ConnectionResult, + StrictSelect, } from '../../orm/select-types'; export type { PostSelect, PostWithRelations, PostFilter, PostsOrderBy } from '../../orm/input-types'; @@ -1163,29 +1381,39 @@ export const postsQueryKey = postKeys.list; * @example * \`\`\`tsx * const { data, isLoading } = usePostsQuery({ - * select: { id: true, name: true }, - * first: 10, - * where: { 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: { first: 10 }, + * scope: { parentId: 'parent-id' }, + * }); * \`\`\` */ -export function usePostsQuery( - args?: FindManyArgs, PostFilter, PostsOrderBy>, - options?: Omit> }, Error>, '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?: (Omit, 'fields'> & { fields?: undefined }) } & Omit> }, Error, TData>, 'queryKey' | 'queryFn'> & { scope?: PostScope } +): UseQueryResult; +export function usePostsQuery( + params?: { selection?: ListSelectionConfig } & Omit, 'queryKey' | 'queryFn'> & { scope?: PostScope } ) { - const { scope, ...queryOptions } = options ?? {}; + const selection = params?.selection; + const args = buildListSelectionArgs(selection); + const { scope, selection: _selection, ...queryOptions } = params ?? {}; + void _selection; return useQuery({ queryKey: postKeys.list(args, scope), - queryFn: () => getClient().post.findMany(args).unwrap(), + queryFn: () => getClient().post.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(), ...queryOptions, }); } @@ -1195,13 +1423,25 @@ export function usePostsQuery * * @example * \`\`\`ts - * const data = await fetchPostsQuery({ first: 10, select: { id: true } }); + * const data = await fetchPostsQuery({ + * selection: { + * fields: { id: true }, + * first: 10, + * }, + * }); * \`\`\` */ -export async function fetchPostsQuery( - args?: FindManyArgs, PostFilter, PostsOrderBy>, +export async function fetchPostsQuery( + params: { selection: ({ fields: S } & Omit, 'fields'> & StrictSelect) } +): Promise<{ posts: ConnectionResult> }>; +export async function fetchPostsQuery( + params?: { selection?: (Omit, 'fields'> & { fields?: undefined }) } +): Promise<{ posts: ConnectionResult> }>; +export async function fetchPostsQuery( + params?: { selection?: ListSelectionConfig } ) { - return getClient().post.findMany(args).unwrap(); + const args = buildListSelectionArgs(params?.selection); + return getClient().post.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(); } /** @@ -1209,17 +1449,25 @@ export async function fetchPostsQuery( +export async function prefetchPostsQuery( + queryClient: QueryClient, + params: { selection: ({ fields: S } & Omit, 'fields'> & StrictSelect) } & { scope?: PostScope } +): Promise; +export async function prefetchPostsQuery( queryClient: QueryClient, - args?: FindManyArgs, PostFilter, PostsOrderBy>, - scope?: PostScope, + params?: { selection?: (Omit, 'fields'> & { fields?: undefined }) } & { 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(args, scope), - queryFn: () => getClient().post.findMany(args).unwrap(), + queryKey: postKeys.list(args, params?.scope), + queryFn: () => getClient().post.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(), }); } " @@ -1233,8 +1481,10 @@ 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 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, @@ -1243,16 +1493,16 @@ import type { } from '../../orm/input-types'; import type { FindManyArgs, - DeepExact, InferSelectResult, ConnectionResult, + StrictSelect, } from '../../orm/select-types'; export type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy } from '../../orm/input-types'; const defaultSelect = { id: true } as const; -export const usersQueryKey = (variables?: FindManyArgs) => ['user', 'list', variables] as const; +export const usersQueryKey = (variables?: FindManyArgs) => ['user', 'list', variables] as const; /** * Query hook for fetching User list @@ -1260,21 +1510,32 @@ export const usersQueryKey = (variables?: FindManyArgs( - args?: FindManyArgs, UserFilter, UsersOrderBy>, - options?: Omit> }, Error>, 'queryKey' | 'queryFn'> +export function useUsersQuery> }>( + params: { selection: ({ fields: S } & Omit, 'fields'> & StrictSelect) } & Omit> }, Error, TData>, 'queryKey' | 'queryFn'> +): UseQueryResult; +export function useUsersQuery> }>( + params?: { selection?: (Omit, 'fields'> & { fields?: undefined }) } & Omit> }, Error, TData>, 'queryKey' | 'queryFn'> +): UseQueryResult; +export function useUsersQuery( + params?: { selection?: ListSelectionConfig } & Omit, 'queryKey' | 'queryFn'> ) { + const selection = params?.selection; + const args = buildListSelectionArgs(selection); + const { selection: _selection, ...queryOptions } = params ?? {}; + void _selection; return useQuery({ queryKey: usersQueryKey(args), - queryFn: () => getClient().user.findMany(args).unwrap(), - ...options, + queryFn: () => getClient().user.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + ...queryOptions, }); } @@ -1283,13 +1544,25 @@ export function useUsersQuery * * @example * \`\`\`ts - * const data = await fetchUsersQuery({ first: 10, select: { id: true } }); + * const data = await fetchUsersQuery({ + * selection: { + * fields: { id: true }, + * first: 10, + * }, + * }); * \`\`\` */ -export async function fetchUsersQuery( - args?: FindManyArgs, UserFilter, UsersOrderBy>, +export async function fetchUsersQuery( + params: { selection: ({ fields: S } & Omit, 'fields'> & StrictSelect) } +): Promise<{ users: ConnectionResult> }>; +export async function fetchUsersQuery( + params?: { selection?: (Omit, 'fields'> & { fields?: undefined }) } +): Promise<{ users: ConnectionResult> }>; +export async function fetchUsersQuery( + params?: { selection?: ListSelectionConfig } ) { - return getClient().user.findMany(args).unwrap(); + const args = buildListSelectionArgs(params?.selection); + return getClient().user.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(); } /** @@ -1297,16 +1570,25 @@ export async function fetchUsersQuery( +export async function prefetchUsersQuery( + queryClient: QueryClient, + params: { selection: ({ fields: S } & Omit, 'fields'> & StrictSelect) } +): Promise; +export async function prefetchUsersQuery( + queryClient: QueryClient, + params?: { selection?: (Omit, 'fields'> & { fields?: undefined }) } +): Promise; +export async function prefetchUsersQuery( queryClient: QueryClient, - args?: FindManyArgs, UserFilter, UsersOrderBy>, + params?: { selection?: ListSelectionConfig } ): Promise { + const args = buildListSelectionArgs(params?.selection); await queryClient.prefetchQuery({ queryKey: usersQueryKey(args), - queryFn: () => getClient().user.findMany(args).unwrap(), + queryFn: () => getClient().user.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), }); } " @@ -1320,16 +1602,18 @@ exports[`Query Hook Generators generateSingleQueryHook generates single query ho */ import { useQuery } from '@tanstack/react-query'; -import type { UseQueryOptions, QueryClient } from '@tanstack/react-query'; +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'; import type { UserSelect, UserWithRelations, } from '../../orm/input-types'; import type { - DeepExact, InferSelectResult, + StrictSelect, } from '../../orm/select-types'; export type { UserSelect, UserWithRelations } from '../../orm/input-types'; @@ -1346,18 +1630,26 @@ export const userQueryKey = userKeys.detail; * \`\`\`tsx * const { data, isLoading } = useUserQuery({ * id: 'some-id', - * select: { id: true, name: true }, + * selection: { fields: { id: true, name: true } }, * }); * \`\`\` */ -export function useUserQuery( - args: { id: string; select?: DeepExact }, - options?: Omit | null }, Error>, 'queryKey' | 'queryFn'> +export function useUserQuery | null }>( + params: { id: string; selection: ({ fields: S } & StrictSelect) } & Omit | null }, Error, TData>, 'queryKey' | 'queryFn'> +): UseQueryResult; +export function useUserQuery | null }>( + params: { id: string; selection?: ({ fields?: undefined }) } & 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(args.id), - queryFn: () => getClient().user.findOne(args).unwrap(), - ...options, + queryKey: userKeys.detail(params.id), + queryFn: () => getClient().user.findOne({ id: params.id, ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + ...queryOptions, }); } @@ -1366,13 +1658,23 @@ export function useUserQuery( * * @example * \`\`\`ts - * const data = await fetchUserQuery({ id: 'some-id', select: { id: true } }); + * const data = await fetchUserQuery({ + * id: 'some-id', + * selection: { fields: { id: true } }, + * }); * \`\`\` */ -export async function fetchUserQuery( - args: { id: string; select?: DeepExact }, +export async function fetchUserQuery( + params: { id: string; selection: ({ fields: S } & StrictSelect) } +): Promise<{ user: InferSelectResult | null }>; +export async function fetchUserQuery( + params: { id: string; selection?: ({ fields?: undefined }) }, +): Promise<{ user: InferSelectResult | null }>; +export async function fetchUserQuery( + params: { id: string; selection?: SelectionConfig }, ) { - return getClient().user.findOne(args).unwrap(); + const args = buildSelectionArgs(params.selection); + return getClient().user.findOne({ id: params.id, ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(); } /** @@ -1383,13 +1685,22 @@ export async function fetchUserQuery( +export async function prefetchUserQuery( + queryClient: QueryClient, + params: { id: string; selection: ({ fields: S } & StrictSelect) }, +): Promise; +export async function prefetchUserQuery( queryClient: QueryClient, - args: { id: string; select?: DeepExact }, + params: { id: string; selection?: ({ fields?: undefined }) }, +): Promise; +export async function prefetchUserQuery( + queryClient: QueryClient, + params: { id: string; selection?: SelectionConfig }, ): Promise { + const args = buildSelectionArgs(params.selection); await queryClient.prefetchQuery({ - queryKey: userKeys.detail(args.id), - queryFn: () => getClient().user.findOne(args).unwrap(), + queryKey: userKeys.detail(params.id), + queryFn: () => getClient().user.findOne({ id: params.id, ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), }); } " @@ -1403,8 +1714,10 @@ exports[`Query Hook Generators generateSingleQueryHook generates single query ho */ import { useQuery } from '@tanstack/react-query'; -import type { UseQueryOptions, QueryClient } from '@tanstack/react-query'; +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'; import type { @@ -1412,8 +1725,8 @@ import type { PostWithRelations, } from '../../orm/input-types'; import type { - DeepExact, InferSelectResult, + StrictSelect, } from '../../orm/select-types'; export type { PostSelect, PostWithRelations } from '../../orm/input-types'; @@ -1430,26 +1743,33 @@ export const postQueryKey = postKeys.detail; * \`\`\`tsx * const { data, isLoading } = usePostQuery({ * id: 'some-id', - * select: { id: true, name: true }, + * 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', + * scope: { parentId: 'parent-id' }, + * }); * \`\`\` */ -export function usePostQuery( - args: { id: string; select?: DeepExact }, - options?: Omit | null }, Error>, '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 | null }>( + params: { id: string; selection?: ({ fields?: undefined }) } & Omit | null }, Error, TData>, 'queryKey' | 'queryFn'> & { scope?: PostScope } +): UseQueryResult; +export function usePostQuery( + params: { id: string; selection?: SelectionConfig } & Omit, 'queryKey' | 'queryFn'> & { scope?: PostScope } ) { - const { scope, ...queryOptions } = options ?? {}; + const args = buildSelectionArgs(params.selection); + const { scope, selection: _selection, ...queryOptions } = params ?? {}; + void _selection; return useQuery({ - queryKey: postKeys.detail(args.id, scope), - queryFn: () => getClient().post.findOne(args).unwrap(), + queryKey: postKeys.detail(params.id, scope), + queryFn: () => getClient().post.findOne({ id: params.id, ...(args ?? {}), select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(), ...queryOptions, }); } @@ -1459,13 +1779,23 @@ export function usePostQuery( * * @example * \`\`\`ts - * const data = await fetchPostQuery({ id: 'some-id', select: { id: true } }); + * const data = await fetchPostQuery({ + * id: 'some-id', + * selection: { fields: { id: true } }, + * }); * \`\`\` */ -export async function fetchPostQuery( - args: { id: string; select?: DeepExact }, +export async function fetchPostQuery( + params: { id: string; selection: ({ fields: S } & StrictSelect) } +): Promise<{ post: InferSelectResult | null }>; +export async function fetchPostQuery( + params: { id: string; selection?: ({ fields?: undefined }) }, +): Promise<{ post: InferSelectResult | null }>; +export async function fetchPostQuery( + params: { id: string; selection?: SelectionConfig }, ) { - return getClient().post.findOne(args).unwrap(); + const args = buildSelectionArgs(params.selection); + return getClient().post.findOne({ id: params.id, ...(args ?? {}), select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(); } /** @@ -1476,14 +1806,22 @@ export async function fetchPostQuery( +export async function prefetchPostQuery( + queryClient: QueryClient, + params: { id: string; selection: ({ fields: S } & StrictSelect) } & { scope?: PostScope }, +): Promise; +export async function prefetchPostQuery( queryClient: QueryClient, - args: { id: string; select?: DeepExact }, - scope?: PostScope, + params: { id: string; selection?: ({ fields?: undefined }) } & { 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(args.id, scope), - queryFn: () => getClient().post.findOne(args).unwrap(), + queryKey: postKeys.detail(params.id, params.scope), + queryFn: () => getClient().post.findOne({ id: params.id, ...(args ?? {}), select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(), }); } " @@ -1497,15 +1835,17 @@ exports[`Query Hook Generators generateSingleQueryHook generates single query ho */ import { useQuery } from '@tanstack/react-query'; -import type { UseQueryOptions, QueryClient } from '@tanstack/react-query'; +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 { - DeepExact, InferSelectResult, + StrictSelect, } from '../../orm/select-types'; export type { UserSelect, UserWithRelations } from '../../orm/input-types'; @@ -1521,18 +1861,26 @@ export const userQueryKey = (id: string) => ['user', 'detail', id] as const; * \`\`\`tsx * const { data, isLoading } = useUserQuery({ * id: 'some-id', - * select: { id: true, name: true }, + * selection: { fields: { id: true, name: true } }, * }); * \`\`\` */ -export function useUserQuery( - args: { id: string; select?: DeepExact }, - options?: Omit | null }, Error>, 'queryKey' | 'queryFn'> +export function useUserQuery | null }>( + params: { id: string; selection: ({ fields: S } & StrictSelect) } & Omit | null }, Error, TData>, 'queryKey' | 'queryFn'> +): UseQueryResult; +export function useUserQuery | null }>( + params: { id: string; selection?: ({ fields?: undefined }) } & 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(args.id), - queryFn: () => getClient().user.findOne(args).unwrap(), - ...options, + queryKey: userQueryKey(params.id), + queryFn: () => getClient().user.findOne({ id: params.id, ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + ...queryOptions, }); } @@ -1541,13 +1889,23 @@ export function useUserQuery( * * @example * \`\`\`ts - * const data = await fetchUserQuery({ id: 'some-id', select: { id: true } }); + * const data = await fetchUserQuery({ + * id: 'some-id', + * selection: { fields: { id: true } }, + * }); * \`\`\` */ -export async function fetchUserQuery( - args: { id: string; select?: DeepExact }, +export async function fetchUserQuery( + params: { id: string; selection: ({ fields: S } & StrictSelect) } +): Promise<{ user: InferSelectResult | null }>; +export async function fetchUserQuery( + params: { id: string; selection?: ({ fields?: undefined }) }, +): Promise<{ user: InferSelectResult | null }>; +export async function fetchUserQuery( + params: { id: string; selection?: SelectionConfig }, ) { - return getClient().user.findOne(args).unwrap(); + const args = buildSelectionArgs(params.selection); + return getClient().user.findOne({ id: params.id, ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(); } /** @@ -1558,13 +1916,22 @@ export async function fetchUserQuery( +export async function prefetchUserQuery( + queryClient: QueryClient, + params: { id: string; selection: ({ fields: S } & StrictSelect) }, +): Promise; +export async function prefetchUserQuery( + queryClient: QueryClient, + params: { id: string; selection?: ({ fields?: undefined }) }, +): Promise; +export async function prefetchUserQuery( queryClient: QueryClient, - args: { id: string; select?: DeepExact }, + params: { id: string; selection?: SelectionConfig }, ): Promise { + const args = buildSelectionArgs(params.selection); await queryClient.prefetchQuery({ - queryKey: userQueryKey(args.id), - queryFn: () => getClient().user.findOne(args).unwrap(), + queryKey: userQueryKey(params.id), + queryFn: () => getClient().user.findOne({ id: params.id, ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), }); } " diff --git a/graphql/codegen/src/__tests__/codegen/query-builder.test.ts b/graphql/codegen/src/__tests__/codegen/query-builder.test.ts index 7c0d3b599..3cd47be84 100644 --- a/graphql/codegen/src/__tests__/codegen/query-builder.test.ts +++ b/graphql/codegen/src/__tests__/codegen/query-builder.test.ts @@ -55,20 +55,55 @@ function addVariable( 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,10 +115,11 @@ 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[] = []; @@ -175,6 +211,155 @@ 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', () => { @@ -222,4 +407,140 @@ 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/core/codegen/custom-mutations.ts b/graphql/codegen/src/core/codegen/custom-mutations.ts index ef4cc4b90..dc28b3ea7 100644 --- a/graphql/codegen/src/core/codegen/custom-mutations.ts +++ b/graphql/codegen/src/core/codegen/custom-mutations.ts @@ -101,8 +101,10 @@ function generateCustomMutationHookInternal( // Imports lines.push(`import { useMutation } from '@tanstack/react-query';`); - lines.push(`import type { UseMutationOptions } from '@tanstack/react-query';`); + lines.push(`import type { UseMutationOptions, UseMutationResult } from '@tanstack/react-query';`); lines.push(`import { getClient } from '../client';`); + lines.push(`import { buildSelectionArgs } from '../selection';`); + lines.push(`import type { SelectionConfig } from '../selection';`); if (useCentralizedKeys) { lines.push(`import { customMutationKeys } from '../mutation-keys';`); @@ -130,7 +132,7 @@ function generateCustomMutationHookInternal( } if (hasSelect) { - lines.push(`import type { DeepExact, InferSelectResult } from '../../orm/select-types';`); + lines.push(`import type { InferSelectResult, StrictSelect } from '../../orm/select-types';`); } lines.push(''); @@ -153,17 +155,28 @@ function generateCustomMutationHookInternal( // Hook if (hasSelect) { - // With select: generic hook - const selectedResult = wrapInferSelectResult(operation.returnType, payloadTypeName); - const resultTypeStr = `{ ${operation.name}: ${selectedResult} }`; + // With selection.fields: overloaded hook for autocompletion + typed options/result const mutationVarType = hasArgs ? varTypeName : 'void'; - - const optionsType = `Omit, 'mutationFn'>`; - - lines.push(`export function ${hookName}(`); - lines.push(` args?: { select?: DeepExact },`); - lines.push(` options?: ${optionsType}`); + const selectedResultType = (s: string) => + `{ ${operation.name}: ${wrapInferSelectResult(operation.returnType, payloadTypeName!, s)} }`; + const mutationOptionsType = (s: string) => + `Omit, 'mutationFn'>`; + const selectionWithFieldsType = (s: string) => + `({ fields: ${s} } & StrictSelect<${s}, ${selectTypeName}>)`; + const selectionWithoutFieldsType = () => `({ fields?: undefined })`; + + lines.push(`export function ${hookName}(`); + lines.push(` params: { selection: ${selectionWithFieldsType('S')} } & ${mutationOptionsType('S')}`); + lines.push(`): UseMutationResult<${selectedResultType('S')}, Error, ${mutationVarType}>;`); + lines.push(`export function ${hookName}(`); + lines.push(` params?: { selection?: ${selectionWithoutFieldsType()} } & ${mutationOptionsType('typeof defaultSelect')}`); + lines.push(`): UseMutationResult<${selectedResultType('typeof defaultSelect')}, Error, ${mutationVarType}>;`); + lines.push(`export function ${hookName}(`); + lines.push(` params?: { selection?: SelectionConfig<${selectTypeName}> } & Omit, 'mutationFn'>`); lines.push(`) {`); + lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); + lines.push(` const { selection: _selection, ...mutationOptions } = params ?? {};`); + lines.push(` void _selection;`); lines.push(` return useMutation({`); if (useCentralizedKeys) { @@ -171,12 +184,12 @@ function generateCustomMutationHookInternal( } if (hasArgs) { - lines.push(` mutationFn: (variables: ${varTypeName}) => getClient().mutation.${operation.name}(variables, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); + lines.push(` mutationFn: (variables: ${varTypeName}) => getClient().mutation.${operation.name}(variables, { select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); } else { - lines.push(` mutationFn: () => getClient().mutation.${operation.name}({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); + lines.push(` mutationFn: () => getClient().mutation.${operation.name}({ select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); } - lines.push(` ...options,`); + lines.push(` ...mutationOptions,`); lines.push(` });`); lines.push(`}`); } else { @@ -186,9 +199,15 @@ function generateCustomMutationHookInternal( const optionsType = `Omit, 'mutationFn'>`; - lines.push(`export function ${hookName}(`); - lines.push(` options?: ${optionsType}`); + if (hasArgs) { + lines.push(`export function ${hookName}(`); + lines.push(` params?: ${optionsType}`); + } else { + lines.push(`export function ${hookName}(`); + lines.push(` params?: ${optionsType}`); + } lines.push(`) {`); + lines.push(` const mutationOptions = params ?? {};`); lines.push(` return useMutation({`); if (useCentralizedKeys) { @@ -201,7 +220,7 @@ function generateCustomMutationHookInternal( lines.push(` mutationFn: () => getClient().mutation.${operation.name}().unwrap(),`); } - lines.push(` ...options,`); + lines.push(` ...mutationOptions,`); lines.push(` });`); lines.push(`}`); } diff --git a/graphql/codegen/src/core/codegen/custom-queries.ts b/graphql/codegen/src/core/codegen/custom-queries.ts index 9c005c5e1..18d11d483 100644 --- a/graphql/codegen/src/core/codegen/custom-queries.ts +++ b/graphql/codegen/src/core/codegen/custom-queries.ts @@ -89,10 +89,12 @@ export function generateCustomQueryHook( // Imports if (reactQueryEnabled) { lines.push(`import { useQuery } from '@tanstack/react-query';`); - lines.push(`import type { UseQueryOptions, QueryClient } from '@tanstack/react-query';`); + lines.push(`import type { UseQueryOptions, UseQueryResult, QueryClient } from '@tanstack/react-query';`); } lines.push(`import { getClient } from '../client';`); + lines.push(`import { buildSelectionArgs } from '../selection';`); + lines.push(`import type { SelectionConfig } from '../selection';`); if (useCentralizedKeys) { lines.push(`import { customQueryKeys } from '../query-keys';`); @@ -124,7 +126,7 @@ export function generateCustomQueryHook( } if (hasSelect) { - lines.push(`import type { DeepExact, InferSelectResult } from '../../orm/select-types';`); + lines.push(`import type { InferSelectResult, StrictSelect } from '../../orm/select-types';`); } lines.push(''); @@ -178,54 +180,91 @@ export function generateCustomQueryHook( lines.push(` */`); if (hasSelect) { - // With select: generic hook - const selectedResult = wrapInferSelectResult(operation.returnType, payloadTypeName); - const resultTypeStr = `{ ${operation.name}: ${selectedResult} }`; - const paramsArr: string[] = []; + // With selection.fields: overloaded hook for autocompletion + const customSelectResultType = (s: string) => + `{ ${operation.name}: ${wrapInferSelectResult(operation.returnType, payloadTypeName!, s)} }`; + const optionsType = (queryData: string, data: string) => + `Omit, 'queryKey' | 'queryFn'>`; + const withFieldsSelectionType = (s: string) => + `({ fields: ${s} } & StrictSelect<${s}, ${selectTypeName}>)`; + const withoutFieldsSelectionType = () => `({ fields?: undefined })`; + + // Overload 1: with selection.fields if (hasArgs) { - paramsArr.push(` variables${hasRequiredArgs ? '' : '?'}: ${varTypeName},`); + const varTypeStr = hasRequiredArgs ? varTypeName : `${varTypeName} | undefined`; + lines.push(`export function ${hookName}(`); + lines.push(` params: { variables: ${varTypeStr}; selection: ${withFieldsSelectionType('S')} } & ${optionsType(customSelectResultType('S'), 'TData')}`); + lines.push(`): UseQueryResult;`); + } else { + lines.push(`export function ${hookName}(`); + lines.push(` params: { selection: ${withFieldsSelectionType('S')} } & ${optionsType(customSelectResultType('S'), 'TData')}`); + lines.push(`): UseQueryResult;`); } - paramsArr.push(` args?: { select?: DeepExact },`); - - const optionsType = `Omit, 'queryKey' | 'queryFn'>`; - paramsArr.push(` options?: ${optionsType}`); - lines.push(`export function ${hookName}(`); - lines.push(paramsArr.join('\n')); - lines.push(`) {`); - lines.push(` return useQuery({`); + // Overload 2: without selection.fields (uses default) + if (hasArgs) { + lines.push(`export function ${hookName}(`); + lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}; selection?: ${withoutFieldsSelectionType()} } & ${optionsType(customSelectResultType('typeof defaultSelect'), 'TData')}`); + lines.push(`): UseQueryResult;`); + } else { + lines.push(`export function ${hookName}(`); + lines.push(` params?: { selection?: ${withoutFieldsSelectionType()} } & ${optionsType(customSelectResultType('typeof defaultSelect'), 'TData')}`); + lines.push(`): UseQueryResult;`); + } + // Implementation if (hasArgs) { + lines.push(`export function ${hookName}(`); + lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}; selection?: SelectionConfig<${selectTypeName}> } & Omit, 'queryKey' | 'queryFn'>`); + lines.push(`) {`); + lines.push(` const variables = params?.variables;`); + lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); + lines.push(` const { variables: _variables, selection: _selection, ...queryOptions } = params ?? {};`); + lines.push(` void _variables;`); + lines.push(` void _selection;`); + lines.push(` return useQuery({`); lines.push(` queryKey: ${queryKeyName}(variables),`); - lines.push(` queryFn: () => getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); + lines.push(` queryFn: () => getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}, { select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); + if (hasRequiredArgs) { + lines.push(` enabled: !!variables && params?.enabled !== false,`); + } + lines.push(` ...queryOptions,`); + lines.push(` });`); + lines.push(`}`); } else { + lines.push(`export function ${hookName}(`); + lines.push(` params?: { selection?: SelectionConfig<${selectTypeName}> } & Omit, 'queryKey' | 'queryFn'>`); + lines.push(`) {`); + lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); + lines.push(` const { selection: _selection, ...queryOptions } = params ?? {};`); + lines.push(` void _selection;`); + lines.push(` return useQuery({`); lines.push(` queryKey: ${queryKeyName}(),`); - lines.push(` queryFn: () => getClient().query.${operation.name}({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); - } - - if (hasRequiredArgs) { - lines.push(` enabled: !!variables && options?.enabled !== false,`); + lines.push(` queryFn: () => getClient().query.${operation.name}({ select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); + lines.push(` ...queryOptions,`); + lines.push(` });`); + lines.push(`}`); } - - lines.push(` ...options,`); - lines.push(` });`); - lines.push(`}`); } else { // Without select: simple hook (scalar return type) const resultTypeStr = `{ ${operation.name}: ${resultType} }`; - const paramsArr: string[] = []; + const optionsType = `Omit, 'queryKey' | 'queryFn'>`; + lines.push(`export function ${hookName}(`); + if (hasArgs) { + lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName} } & ${optionsType}`); + } else { + lines.push(` params?: ${optionsType}`); + } + lines.push(`): UseQueryResult {`); if (hasArgs) { - paramsArr.push(` variables${hasRequiredArgs ? '' : '?'}: ${varTypeName},`); + lines.push(` const variables = params?.variables;`); + lines.push(` const { variables: _variables, ...queryOptions } = params ?? {};`); + lines.push(` void _variables;`); + } else { + lines.push(` const queryOptions = params ?? {};`); } - - const optionsType = `Omit, 'queryKey' | 'queryFn'>`; - paramsArr.push(` options?: ${optionsType}`); - - lines.push(`export function ${hookName}(`); - lines.push(paramsArr.join('\n')); - lines.push(`) {`); lines.push(` return useQuery({`); if (hasArgs) { @@ -237,10 +276,10 @@ export function generateCustomQueryHook( } if (hasRequiredArgs) { - lines.push(` enabled: !!variables && options?.enabled !== false,`); + lines.push(` enabled: !!variables && params?.enabled !== false,`); } - lines.push(` ...options,`); + lines.push(` ...queryOptions,`); lines.push(` });`); lines.push(`}`); } @@ -263,36 +302,55 @@ export function generateCustomQueryHook( lines.push(` */`); if (hasSelect) { - const fetchParamsArr: string[] = []; - if (hasArgs) { - fetchParamsArr.push(`variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}`); - } - fetchParamsArr.push(`args?: { select?: DeepExact }`); + const customSelectResultType = (s: string) => + `{ ${operation.name}: ${wrapInferSelectResult(operation.returnType, payloadTypeName!, s)} }`; + const withFieldsSelectionType = (s: string) => + `({ fields: ${s} } & StrictSelect<${s}, ${selectTypeName}>)`; + const withoutFieldsSelectionType = () => `({ fields?: undefined })`; - lines.push(`export async function ${fetchFnName}(`); - lines.push(` ${fetchParamsArr.join(',\n ')}`); - lines.push(`) {`); if (hasArgs) { - lines.push(` return getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap();`); + const requiredVarType = hasRequiredArgs ? varTypeName : `${varTypeName} | undefined`; + + lines.push(`export async function ${fetchFnName}(`); + lines.push(` params: { variables: ${requiredVarType}; selection: ${withFieldsSelectionType('S')} }`); + lines.push(`): Promise<${customSelectResultType('S')}>;`); + lines.push(`export async function ${fetchFnName}(`); + lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}; selection?: ${withoutFieldsSelectionType()} }`); + lines.push(`): Promise<${customSelectResultType('typeof defaultSelect')}>;`); + lines.push(`export async function ${fetchFnName}(`); + lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}; selection?: SelectionConfig<${selectTypeName}> },`); + lines.push(`) {`); + lines.push(` const variables = params?.variables;`); + lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); + lines.push(` return getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}, { select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap();`); + lines.push(`}`); } else { - lines.push(` return getClient().query.${operation.name}({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap();`); + lines.push(`export async function ${fetchFnName}(`); + lines.push(` params: { selection: ${withFieldsSelectionType('S')} }`); + lines.push(`): Promise<${customSelectResultType('S')}>;`); + lines.push(`export async function ${fetchFnName}(`); + lines.push(` params?: { selection?: ${withoutFieldsSelectionType()} },`); + lines.push(`): Promise<${customSelectResultType('typeof defaultSelect')}>;`); + lines.push(`export async function ${fetchFnName}(`); + lines.push(` params?: { selection?: SelectionConfig<${selectTypeName}> },`); + lines.push(`) {`); + lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); + lines.push(` return getClient().query.${operation.name}({ select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap();`); + lines.push(`}`); } - lines.push(`}`); } else { - const fetchParamsArr: string[] = []; - if (hasArgs) { - fetchParamsArr.push(`variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}`); - } - - lines.push(`export async function ${fetchFnName}(`); - lines.push(` ${fetchParamsArr.join(',\n ')}`); - lines.push(`) {`); if (hasArgs) { + lines.push(`export async function ${fetchFnName}(`); + lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName} }`); + lines.push(`) {`); + lines.push(` const variables = params?.variables;`); lines.push(` return getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}).unwrap();`); + lines.push(`}`); } else { + lines.push(`export async function ${fetchFnName}() {`); lines.push(` return getClient().query.${operation.name}().unwrap();`); + lines.push(`}`); } - lines.push(`}`); } // Prefetch function @@ -315,52 +373,72 @@ export function generateCustomQueryHook( lines.push(` */`); if (hasSelect) { - const prefetchParamsArr: string[] = ['queryClient: QueryClient']; - if (hasArgs) { - prefetchParamsArr.push(`variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}`); - } - prefetchParamsArr.push(`args?: { select?: DeepExact }`); - - lines.push(`export async function ${prefetchFnName}(`); - lines.push(` ${prefetchParamsArr.join(',\n ')}`); - lines.push(`): Promise {`); + const withFieldsSelectionType = (s: string) => + `({ fields: ${s} } & StrictSelect<${s}, ${selectTypeName}>)`; + const withoutFieldsSelectionType = () => `({ fields?: undefined })`; if (hasArgs) { + const requiredVarType = hasRequiredArgs ? varTypeName : `${varTypeName} | undefined`; + + lines.push(`export async function ${prefetchFnName}(`); + lines.push(` queryClient: QueryClient,`); + lines.push(` params: { variables: ${requiredVarType}; selection: ${withFieldsSelectionType('S')} }`); + lines.push(`): Promise;`); + lines.push(`export async function ${prefetchFnName}(`); + lines.push(` queryClient: QueryClient,`); + lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}; selection?: ${withoutFieldsSelectionType()} }`); + lines.push(`): Promise;`); + lines.push(`export async function ${prefetchFnName}(`); + lines.push(` queryClient: QueryClient,`); + lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}; selection?: SelectionConfig<${selectTypeName}> }`); + lines.push(`): Promise {`); + lines.push(` const variables = params?.variables;`); + lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); lines.push(` await queryClient.prefetchQuery({`); lines.push(` queryKey: ${queryKeyName}(variables),`); - lines.push(` queryFn: () => getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}, { select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); + lines.push(` queryFn: () => getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}, { select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); lines.push(` });`); + lines.push(`}`); } else { + lines.push(`export async function ${prefetchFnName}(`); + lines.push(` queryClient: QueryClient,`); + lines.push(` params: { selection: ${withFieldsSelectionType('S')} }`); + lines.push(`): Promise;`); + lines.push(`export async function ${prefetchFnName}(`); + lines.push(` queryClient: QueryClient,`); + lines.push(` params?: { selection?: ${withoutFieldsSelectionType()} }`); + lines.push(`): Promise;`); + lines.push(`export async function ${prefetchFnName}(`); + lines.push(` queryClient: QueryClient,`); + lines.push(` params?: { selection?: SelectionConfig<${selectTypeName}> }`); + lines.push(`): Promise {`); + lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); lines.push(` await queryClient.prefetchQuery({`); lines.push(` queryKey: ${queryKeyName}(),`); - lines.push(` queryFn: () => getClient().query.${operation.name}({ select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); + lines.push(` queryFn: () => getClient().query.${operation.name}({ select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); lines.push(` });`); + lines.push(`}`); } - - lines.push(`}`); } else { - const prefetchParamsArr: string[] = ['queryClient: QueryClient']; - if (hasArgs) { - prefetchParamsArr.push(`variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}`); - } - - lines.push(`export async function ${prefetchFnName}(`); - lines.push(` ${prefetchParamsArr.join(',\n ')}`); - lines.push(`): Promise {`); - if (hasArgs) { + lines.push(`export async function ${prefetchFnName}(`); + lines.push(` queryClient: QueryClient,`); + lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName} }`); + lines.push(`): Promise {`); + lines.push(` const variables = params?.variables;`); lines.push(` await queryClient.prefetchQuery({`); lines.push(` queryKey: ${queryKeyName}(variables),`); lines.push(` queryFn: () => getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}).unwrap(),`); lines.push(` });`); + lines.push(`}`); } else { + lines.push(`export async function ${prefetchFnName}(queryClient: QueryClient): Promise {`); lines.push(` await queryClient.prefetchQuery({`); lines.push(` queryKey: ${queryKeyName}(),`); lines.push(` queryFn: () => getClient().query.${operation.name}().unwrap(),`); lines.push(` });`); + lines.push(`}`); } - - lines.push(`}`); } } diff --git a/graphql/codegen/src/core/codegen/index.ts b/graphql/codegen/src/core/codegen/index.ts index b77bad93d..57e75750f 100644 --- a/graphql/codegen/src/core/codegen/index.ts +++ b/graphql/codegen/src/core/codegen/index.ts @@ -44,6 +44,7 @@ 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'; // ============================================================================ @@ -129,6 +130,12 @@ export function generate(options: GenerateOptions): GenerateResult { 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)); diff --git a/graphql/codegen/src/core/codegen/mutations.ts b/graphql/codegen/src/core/codegen/mutations.ts index 8e368337e..078521e49 100644 --- a/graphql/codegen/src/core/codegen/mutations.ts +++ b/graphql/codegen/src/core/codegen/mutations.ts @@ -64,8 +64,10 @@ export function generateCreateMutationHook( // Imports lines.push(`import { useMutation, useQueryClient } from '@tanstack/react-query';`); - lines.push(`import type { UseMutationOptions } from '@tanstack/react-query';`); + lines.push(`import type { UseMutationOptions, UseMutationResult } from '@tanstack/react-query';`); lines.push(`import { getClient } from '../client';`); + lines.push(`import { buildSelectionArgs } from '../selection';`); + lines.push(`import type { SelectionConfig } from '../selection';`); if (useCentralizedKeys) { lines.push(`import { ${keysName} } from '../query-keys';`); @@ -77,10 +79,7 @@ export function generateCreateMutationHook( lines.push(` ${relationTypeName},`); lines.push(` ${createInputTypeName},`); lines.push(`} from '../../orm/input-types';`); - lines.push(`import type {`); - lines.push(` DeepExact,`); - lines.push(` InferSelectResult,`); - lines.push(`} from '../../orm/select-types';`); + lines.push(`import type { InferSelectResult, StrictSelect } from '../../orm/select-types';`); lines.push(''); // Re-export types @@ -97,16 +96,30 @@ export function generateCreateMutationHook( lines.push(` * @example`); lines.push(` * \`\`\`tsx`); lines.push(` * const { mutate, isPending } = ${hookName}({`); - lines.push(` * select: { id: true, name: true },`); + lines.push(` * selection: { fields: { id: true, name: true } },`); lines.push(` * });`); lines.push(` *`); lines.push(` * mutate({ name: 'New item' });`); lines.push(` * \`\`\``); lines.push(` */`); - lines.push(`export function ${hookName}(`); - lines.push(` args?: { select?: DeepExact },`); - lines.push(` options?: Omit } }, Error, ${createInputTypeName}['${singularName}']>, 'mutationFn'>`); + const createResultType = (s: string) => `{ ${mutationName}: { ${singularName}: InferSelectResult<${relationTypeName}, ${s}> } }`; + const createVarType = `${createInputTypeName}['${singularName}']`; + const createOptionsType = (s: string) => `Omit, 'mutationFn'>`; + const selectionWithFieldsType = (s: string) => + `({ fields: ${s} } & StrictSelect<${s}, ${selectTypeName}>)`; + const selectionWithoutFieldsType = () => `({ fields?: undefined })`; + lines.push(`export function ${hookName}(`); + lines.push(` params: { selection: ${selectionWithFieldsType('S')} } & ${createOptionsType('S')}`); + lines.push(`): UseMutationResult<${createResultType('S')}, Error, ${createVarType}>;`); + lines.push(`export function ${hookName}(`); + lines.push(` params?: { selection?: ${selectionWithoutFieldsType()} } & ${createOptionsType('typeof defaultSelect')}`); + lines.push(`): UseMutationResult<${createResultType('typeof defaultSelect')}, Error, ${createVarType}>;`); + lines.push(`export function ${hookName}(`); + lines.push(` params?: { selection?: SelectionConfig<${selectTypeName}> } & Omit, 'mutationFn'>`); lines.push(`) {`); + lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); + lines.push(` const { selection: _selection, ...mutationOptions } = params ?? {};`); + lines.push(` void _selection;`); lines.push(` const queryClient = useQueryClient();`); lines.push(` return useMutation({`); @@ -114,7 +127,7 @@ export function generateCreateMutationHook( lines.push(` mutationKey: ${mutationKeysName}.create(),`); } - lines.push(` mutationFn: (data: ${createInputTypeName}['${singularName}']) => getClient().${singularName}.create({ data, select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); + lines.push(` mutationFn: (data: ${createInputTypeName}['${singularName}']) => getClient().${singularName}.create({ data, select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); const listKey = useCentralizedKeys ? `${keysName}.lists()` @@ -122,7 +135,7 @@ export function generateCreateMutationHook( lines.push(` onSuccess: () => {`); lines.push(` queryClient.invalidateQueries({ queryKey: ${listKey} });`); lines.push(` },`); - lines.push(` ...options,`); + lines.push(` ...mutationOptions,`); lines.push(` });`); lines.push(`}`); @@ -171,8 +184,10 @@ export function generateUpdateMutationHook( // Imports lines.push(`import { useMutation, useQueryClient } from '@tanstack/react-query';`); - lines.push(`import type { UseMutationOptions } from '@tanstack/react-query';`); + lines.push(`import type { UseMutationOptions, UseMutationResult } from '@tanstack/react-query';`); lines.push(`import { getClient } from '../client';`); + lines.push(`import { buildSelectionArgs } from '../selection';`); + lines.push(`import type { SelectionConfig } from '../selection';`); if (useCentralizedKeys) { lines.push(`import { ${keysName} } from '../query-keys';`); @@ -184,10 +199,7 @@ export function generateUpdateMutationHook( lines.push(` ${relationTypeName},`); lines.push(` ${patchTypeName},`); lines.push(`} from '../../orm/input-types';`); - lines.push(`import type {`); - lines.push(` DeepExact,`); - lines.push(` InferSelectResult,`); - lines.push(`} from '../../orm/select-types';`); + lines.push(`import type { InferSelectResult, StrictSelect } from '../../orm/select-types';`); lines.push(''); // Re-export types @@ -204,16 +216,30 @@ export function generateUpdateMutationHook( lines.push(` * @example`); lines.push(` * \`\`\`tsx`); lines.push(` * const { mutate, isPending } = ${hookName}({`); - lines.push(` * select: { id: true, name: true },`); + lines.push(` * selection: { fields: { id: true, name: true } },`); lines.push(` * });`); lines.push(` *`); lines.push(` * mutate({ ${pkField.name}: 'value-here', patch: { name: 'Updated' } });`); lines.push(` * \`\`\``); lines.push(` */`); - lines.push(`export function ${hookName}(`); - lines.push(` args?: { select?: DeepExact },`); - lines.push(` options?: Omit } }, Error, { ${pkField.name}: ${pkField.tsType}; patch: ${patchTypeName} }>, 'mutationFn'>`); + const updateResultType = (s: string) => `{ ${mutationName}: { ${singularName}: InferSelectResult<${relationTypeName}, ${s}> } }`; + const updateVarType = `{ ${pkField.name}: ${pkField.tsType}; patch: ${patchTypeName} }`; + const updateOptionsType = (s: string) => `Omit, 'mutationFn'>`; + const selectionWithFieldsType = (s: string) => + `({ fields: ${s} } & StrictSelect<${s}, ${selectTypeName}>)`; + const selectionWithoutFieldsType = () => `({ fields?: undefined })`; + lines.push(`export function ${hookName}(`); + lines.push(` params: { selection: ${selectionWithFieldsType('S')} } & ${updateOptionsType('S')}`); + lines.push(`): UseMutationResult<${updateResultType('S')}, Error, ${updateVarType}>;`); + lines.push(`export function ${hookName}(`); + lines.push(` params?: { selection?: ${selectionWithoutFieldsType()} } & ${updateOptionsType('typeof defaultSelect')}`); + lines.push(`): UseMutationResult<${updateResultType('typeof defaultSelect')}, Error, ${updateVarType}>;`); + lines.push(`export function ${hookName}(`); + lines.push(` params?: { selection?: SelectionConfig<${selectTypeName}> } & Omit, 'mutationFn'>`); lines.push(`) {`); + lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); + lines.push(` const { selection: _selection, ...mutationOptions } = params ?? {};`); + lines.push(` void _selection;`); lines.push(` const queryClient = useQueryClient();`); lines.push(` return useMutation({`); @@ -221,7 +247,7 @@ export function generateUpdateMutationHook( lines.push(` mutationKey: ${mutationKeysName}.all,`); } - lines.push(` mutationFn: ({ ${pkField.name}, patch }: { ${pkField.name}: ${pkField.tsType}; patch: ${patchTypeName} }) => getClient().${singularName}.update({ where: { ${pkField.name} }, data: patch, select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); + lines.push(` mutationFn: ({ ${pkField.name}, patch }: { ${pkField.name}: ${pkField.tsType}; patch: ${patchTypeName} }) => getClient().${singularName}.update({ where: { ${pkField.name} }, data: patch, select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); const detailKey = useCentralizedKeys ? `${keysName}.detail(variables.${pkField.name})` @@ -234,7 +260,7 @@ export function generateUpdateMutationHook( lines.push(` queryClient.invalidateQueries({ queryKey: ${detailKey} });`); lines.push(` queryClient.invalidateQueries({ queryKey: ${listKey} });`); lines.push(` },`); - lines.push(` ...options,`); + lines.push(` ...mutationOptions,`); lines.push(` });`); lines.push(`}`); @@ -282,8 +308,10 @@ export function generateDeleteMutationHook( // Imports lines.push(`import { useMutation, useQueryClient } from '@tanstack/react-query';`); - lines.push(`import type { UseMutationOptions } from '@tanstack/react-query';`); + lines.push(`import type { UseMutationOptions, UseMutationResult } from '@tanstack/react-query';`); lines.push(`import { getClient } from '../client';`); + lines.push(`import { buildSelectionArgs } from '../selection';`); + lines.push(`import type { SelectionConfig } from '../selection';`); if (useCentralizedKeys) { lines.push(`import { ${keysName} } from '../query-keys';`); @@ -294,10 +322,7 @@ export function generateDeleteMutationHook( lines.push(` ${selectTypeName},`); lines.push(` ${relationTypeName},`); lines.push(`} from '../../orm/input-types';`); - lines.push(`import type {`); - lines.push(` DeepExact,`); - lines.push(` InferSelectResult,`); - lines.push(`} from '../../orm/select-types';`); + lines.push(`import type { InferSelectResult, StrictSelect } from '../../orm/select-types';`); lines.push(''); // Re-export types @@ -314,16 +339,30 @@ export function generateDeleteMutationHook( lines.push(` * @example`); lines.push(` * \`\`\`tsx`); lines.push(` * const { mutate, isPending } = ${hookName}({`); - lines.push(` * select: { id: true },`); + lines.push(` * selection: { fields: { id: true } },`); lines.push(` * });`); lines.push(` *`); lines.push(` * mutate({ ${pkField.name}: ${pkField.tsType === 'string' ? "'value-to-delete'" : '123'} });`); lines.push(` * \`\`\``); lines.push(` */`); - lines.push(`export function ${hookName}(`); - lines.push(` args?: { select?: DeepExact },`); - lines.push(` options?: Omit } }, Error, { ${pkField.name}: ${pkField.tsType} }>, 'mutationFn'>`); + const deleteResultType = (s: string) => `{ ${mutationName}: { ${singularName}: InferSelectResult<${relationTypeName}, ${s}> } }`; + const deleteVarType = `{ ${pkField.name}: ${pkField.tsType} }`; + const deleteOptionsType = (s: string) => `Omit, 'mutationFn'>`; + const selectionWithFieldsType = (s: string) => + `({ fields: ${s} } & StrictSelect<${s}, ${selectTypeName}>)`; + const selectionWithoutFieldsType = () => `({ fields?: undefined })`; + lines.push(`export function ${hookName}(`); + lines.push(` params: { selection: ${selectionWithFieldsType('S')} } & ${deleteOptionsType('S')}`); + lines.push(`): UseMutationResult<${deleteResultType('S')}, Error, ${deleteVarType}>;`); + lines.push(`export function ${hookName}(`); + lines.push(` params?: { selection?: ${selectionWithoutFieldsType()} } & ${deleteOptionsType('typeof defaultSelect')}`); + lines.push(`): UseMutationResult<${deleteResultType('typeof defaultSelect')}, Error, ${deleteVarType}>;`); + lines.push(`export function ${hookName}(`); + lines.push(` params?: { selection?: SelectionConfig<${selectTypeName}> } & Omit, 'mutationFn'>`); lines.push(`) {`); + lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); + lines.push(` const { selection: _selection, ...mutationOptions } = params ?? {};`); + lines.push(` void _selection;`); lines.push(` const queryClient = useQueryClient();`); lines.push(` return useMutation({`); @@ -331,7 +370,7 @@ export function generateDeleteMutationHook( lines.push(` mutationKey: ${mutationKeysName}.all,`); } - lines.push(` mutationFn: ({ ${pkField.name} }: { ${pkField.name}: ${pkField.tsType} }) => getClient().${singularName}.delete({ where: { ${pkField.name} }, select: (args?.select ?? defaultSelect) as DeepExact }).unwrap(),`); + lines.push(` mutationFn: ({ ${pkField.name} }: { ${pkField.name}: ${pkField.tsType} }) => getClient().${singularName}.delete({ where: { ${pkField.name} }, select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); const detailKey = useCentralizedKeys ? `${keysName}.detail(variables.${pkField.name})` @@ -344,7 +383,7 @@ export function generateDeleteMutationHook( lines.push(` queryClient.removeQueries({ queryKey: ${detailKey} });`); lines.push(` queryClient.invalidateQueries({ queryKey: ${listKey} });`); lines.push(` },`); - lines.push(` ...options,`); + lines.push(` ...mutationOptions,`); lines.push(` });`); lines.push(`}`); 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 e38554296..5fbcf5f26 100644 --- a/graphql/codegen/src/core/codegen/orm/custom-ops-generator.ts +++ b/graphql/codegen/src/core/codegen/orm/custom-ops-generator.ts @@ -267,26 +267,21 @@ function buildOperationMethod( const optionsParam = t.identifier('options'); optionsParam.optional = true; 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 { @@ -318,6 +313,9 @@ function buildOperationMethod( defaultSelectIdent ) : 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), @@ -338,7 +336,9 @@ function buildOperationMethod( t.objectProperty(t.identifier('type'), t.stringLiteral(v.type)) ]) ) - ) + ), + t.identifier('connectionFieldsMap'), + entityTypeExpr ]) ) ]); @@ -383,7 +383,6 @@ function buildOperationMethod( defaultType, 'S' ); - (typeParam as any).const = true; arrowFunc.typeParameters = t.tsTypeParameterDeclaration([typeParam]); } @@ -409,11 +408,12 @@ export function generateCustomQueryOpsFile( // 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('../select-types', ['InferSelectResult', 'StrictSelect'], true)); if (allTypeImports.length > 0) { statements.push(createImportDeclaration('../input-types', allTypeImports, true)); } + statements.push(createImportDeclaration('../input-types', ['connectionFieldsMap'])); // Generate variable interfaces for (const op of operations) { @@ -486,11 +486,12 @@ export function generateCustomMutationOpsFile( // 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('../select-types', ['InferSelectResult', 'StrictSelect'], true)); if (allTypeImports.length > 0) { statements.push(createImportDeclaration('../input-types', allTypeImports, true)); } + statements.push(createImportDeclaration('../input-types', ['connectionFieldsMap'])); // Generate variable interfaces for (const op of operations) { 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 ee3468f4f..b4cb1bfe4 100644 --- a/graphql/codegen/src/core/codegen/orm/input-types-generator.ts +++ b/graphql/codegen/src/core/codegen/orm/input-types-generator.ts @@ -1596,6 +1596,90 @@ function generatePayloadTypes( 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) // ============================================================================ @@ -1610,39 +1694,44 @@ export function generateInputTypesFile( 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( diff --git a/graphql/codegen/src/core/codegen/orm/model-generator.ts b/graphql/codegen/src/core/codegen/orm/model-generator.ts index 5b05c3e41..67f8a29a5 100644 --- a/graphql/codegen/src/core/codegen/orm/model-generator.ts +++ b/graphql/codegen/src/core/codegen/orm/model-generator.ts @@ -2,6 +2,7 @@ * 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 * as t from '@babel/types'; @@ -84,7 +85,23 @@ function createClassMethod( return method; } -function createConstTypeParam( +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 { @@ -93,7 +110,6 @@ function createConstTypeParam( defaultType ?? null, 'S' ); - (param as any).const = true; return t.tsTypeParameterDeclaration([param]); } @@ -104,6 +120,51 @@ function tsTypeFromPrimitive(typeName: string): t.TSType { 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 an optional `select?: undefined` prop to forbid select in fallback overloads */ +function optionalUndefinedSelectProp(): t.TSPropertySignature { + const prop = t.tsPropertySignature( + t.identifier('select'), + t.tsTypeAnnotation(t.tsUndefinedKeyword()) + ); + prop.optional = true; + 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)) + ]) + ); +} + +/** Build `Omit & { select?: undefined }` for fallback overloads */ +function withoutSelect(argsType: t.TSType): t.TSType { + return t.tsIntersectionType([ + t.tsTypeReference( + t.identifier('Omit'), + t.tsTypeParameterInstantiation([ + argsType, + t.tsLiteralType(t.stringLiteral('select')) + ]) + ), + t.tsTypeLiteral([optionalUndefinedSelectProp()]) + ]); +} + export function generateModelFile( table: CleanTable, _useSharedTypes: boolean @@ -125,7 +186,6 @@ export function generateModelFile( const pkFields = getPrimaryKeyInfo(table); const pkField = pkFields[0]; - const pkFieldTsType = tsTypeFromPrimitive(pkField.tsType); const defaultSelectIdent = t.identifier('defaultSelect'); const defaultSelectFieldName = getDefaultSelectFieldName(table); @@ -143,12 +203,13 @@ export function generateModelFile( ])); statements.push(createImportDeclaration('../select-types', [ 'ConnectionResult', 'FindManyArgs', 'FindFirstArgs', 'CreateArgs', - 'UpdateArgs', 'DeleteArgs', 'InferSelectResult', 'DeepExact' + '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'])); // Default select (ensures valid GraphQL selection + sound TS return types) statements.push( @@ -173,309 +234,407 @@ export function generateModelFile( 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)) - ])) - ); - 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 defaultRef = () => t.tsTypeQuery(defaultSelectIdent); + 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 findManySelectExpr = t.logicalExpression( - '??', - t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), - defaultSelectIdent - ); - const findManyArgs = [ - t.stringLiteral(typeName), - t.stringLiteral(pluralQueryName), - findManySelectExpr, - 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, t.tsTypeQuery(defaultSelectIdent)), [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( + ); + classBody.push(createDeclareMethod('findMany', createTypeParam(selectTypeName), [o1Param], retType(sRef()))); + + // Overload 2: without select (default) + const o2Param = t.identifier('args'); + o2Param.optional = true; + o2Param.typeAnnotation = t.tsTypeAnnotation(withoutSelect(argsType(selectRef()))); + classBody.push(createDeclareMethod('findMany', null, [o2Param], retType(defaultRef()))); + + // Implementation + const implParam = t.identifier('args'); + implParam.optional = true; + implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef())); + const selectExpr = t.logicalExpression('??', + t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), + defaultSelectIdent); + 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)) + ]), + 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('nodes'), t.tsTypeAnnotation( - t.tsArrayType(t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier(relationTypeName)), - t.tsTypeReference(t.identifier('S')) - ]))) + 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) ]) - ])) - ); - const findFirstSelectExpr = t.logicalExpression( - '??', - t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), - defaultSelectIdent - ); - const findFirstArgs = [ - t.stringLiteral(typeName), - t.stringLiteral(pluralQueryName), - findFirstSelectExpr, - 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, t.tsTypeQuery(defaultSelectIdent)), [findFirstParam], findFirstReturnType, - buildMethodBody('buildFindFirstDocument', findFirstArgs, 'query', typeName, pluralQueryName))); - - // findOne method (only if table has valid PK and singular query) + ); + classBody.push(createDeclareMethod('findFirst', createTypeParam(selectTypeName), [o1Param], retType(sRef()))); + + // Overload 2: without select (default) + const o2Param = t.identifier('args'); + o2Param.optional = true; + o2Param.typeAnnotation = t.tsTypeAnnotation(withoutSelect(argsType(selectRef()))); + classBody.push(createDeclareMethod('findFirst', null, [o2Param], retType(defaultRef()))); + + // Implementation + const implParam = t.identifier('args'); + implParam.optional = true; + implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef())); + const selectExpr = t.logicalExpression('??', + t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), + defaultSelectIdent); + 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 findOneParam = t.identifier('args'); - findOneParam.typeAnnotation = t.tsTypeAnnotation( + 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()))); + + // Overload 2: without select (default) + const o2Param = t.identifier('args'); + o2Param.typeAnnotation = t.tsTypeAnnotation( + t.tsTypeLiteral([pkProp()]) + ); + classBody.push(createDeclareMethod('findOne', null, [o2Param], retType(defaultRef()))); + + // Implementation + const implParam = t.identifier('args'); + implParam.typeAnnotation = t.tsTypeAnnotation( t.tsTypeLiteral([ - (() => { - const prop = t.tsPropertySignature( - t.identifier(pkField.name), - t.tsTypeAnnotation(pkFieldTsType) - ); - prop.optional = false; - return prop; - })(), + pkProp(), (() => { 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)) - ])) - ) + t.tsTypeAnnotation(t.tsTypeReference(t.identifier(selectTypeName))) ); prop.optional = true; return prop; })() ]) ); - const findOneReturnType = 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)), - t.tsTypeReference(t.identifier('S')) - ])), - t.tsNullKeyword() - ]) - )) - ]) - ])) - ); - const findOneSelectExpr = t.logicalExpression( - '??', + const selectExpr = t.logicalExpression('??', t.memberExpression(t.identifier('args'), t.identifier('select')), - defaultSelectIdent - ); - const findOneArgs = [ + defaultSelectIdent); + const bodyArgs = [ t.stringLiteral(typeName), t.stringLiteral(singleQueryName), t.memberExpression(t.identifier('args'), t.identifier(pkField.name)), - findOneSelectExpr, + selectExpr, t.stringLiteral(pkField.name), - t.stringLiteral(pkGqlType) + t.stringLiteral(pkGqlType), + t.identifier('connectionFieldsMap') ]; - classBody.push(createClassMethod('findOne', createConstTypeParam(selectTypeName, t.tsTypeQuery(defaultSelectIdent)), [findOneParam], findOneReturnType, - buildMethodBody('buildFindOneDocument', findOneArgs, 'query', typeName, singleQueryName))); + classBody.push(createClassMethod('findOne', null, [implParam], null, + buildMethodBody('buildFindOneDocument', bodyArgs, 'query', typeName, singleQueryName))); } - // 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.tsTypeLiteral([ - t.tsPropertySignature(t.identifier(createMutationName), t.tsTypeAnnotation( + // ── 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) ]) - ])) - ); - const createSelectExpr = t.logicalExpression( - '??', - t.memberExpression(t.identifier('args'), t.identifier('select')), - defaultSelectIdent - ); - const createArgs = [ - t.stringLiteral(typeName), - t.stringLiteral(createMutationName), - t.stringLiteral(entityLower), - createSelectExpr, - t.memberExpression(t.identifier('args'), t.identifier('data')), - t.stringLiteral(createInputTypeName) - ]; - classBody.push(createClassMethod('create', createConstTypeParam(selectTypeName, t.tsTypeQuery(defaultSelectIdent)), [createParam], createReturnType, - buildMethodBody('buildCreateDocument', createArgs, 'mutation', typeName, createMutationName))); - - // update method (if available) + ); + classBody.push(createDeclareMethod('create', createTypeParam(selectTypeName), [o1Param], retType(sRef()))); + + // Overload 2: without select (default) + const o2Param = t.identifier('args'); + o2Param.typeAnnotation = t.tsTypeAnnotation(withoutSelect(argsType(selectRef()))); + classBody.push(createDeclareMethod('create', null, [o2Param], retType(defaultRef()))); + + // Implementation + const implParam = t.identifier('args'); + implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef())); + const selectExpr = t.logicalExpression('??', + t.memberExpression(t.identifier('args'), t.identifier('select')), + defaultSelectIdent); + 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 updateParam = t.identifier('args'); - updateParam.typeAnnotation = 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('UpdateArgs'), t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier('DeepExact'), t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier('S')), - t.tsTypeReference(t.identifier(selectTypeName)) - ])), - t.tsTypeLiteral([ - (() => { - const prop = t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkFieldTsType)); - prop.optional = false; - return prop; - })() - ]), - 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( - 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')) - ])) - )) - ]) - )) - ]) - ])) + 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 updateSelectExpr = t.logicalExpression( - '??', + classBody.push(createDeclareMethod('update', createTypeParam(selectTypeName), [o1Param], retType(sRef()))); + + // Overload 2: without select (default) + const o2Param = t.identifier('args'); + o2Param.typeAnnotation = t.tsTypeAnnotation(withoutSelect(argsType(selectRef()))); + classBody.push(createDeclareMethod('update', null, [o2Param], retType(defaultRef()))); + + // Implementation + const implParam = t.identifier('args'); + implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef())); + const selectExpr = t.logicalExpression('??', t.memberExpression(t.identifier('args'), t.identifier('select')), - defaultSelectIdent - ); - const updateArgs = [ + defaultSelectIdent); + const bodyArgs = [ t.stringLiteral(typeName), t.stringLiteral(updateMutationName), t.stringLiteral(entityLower), - updateSelectExpr, + 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.stringLiteral(pkField.name), + t.identifier('connectionFieldsMap') ]; - classBody.push(createClassMethod('update', createConstTypeParam(selectTypeName, t.tsTypeQuery(defaultSelectIdent)), [updateParam], updateReturnType, - buildMethodBody('buildUpdateByPkDocument', updateArgs, 'mutation', typeName, updateMutationName))); + classBody.push(createClassMethod('update', null, [implParam], null, + buildMethodBody('buildUpdateByPkDocument', bodyArgs, 'mutation', typeName, updateMutationName))); } - // delete method (if available) - supports optional select for returning entity fields + // ── delete ───────────────────────────────────────────────────────────── if (deleteMutationName) { - const deleteParam = t.identifier('args'); - deleteParam.typeAnnotation = t.tsTypeAnnotation( - t.tsTypeReference(t.identifier('DeleteArgs'), t.tsTypeParameterInstantiation([ - t.tsTypeLiteral([ - (() => { - const prop = t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkFieldTsType)); - prop.optional = false; - return prop; - })() - ]), - t.tsTypeReference(t.identifier('DeepExact'), t.tsTypeParameterInstantiation([ - t.tsTypeReference(t.identifier('S')), - t.tsTypeReference(t.identifier(selectTypeName)) + 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(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 + ])) + )) + ]) + )) + ]) ])) - ])) - ); - const deleteReturnType = t.tsTypeAnnotation( - t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([ - t.tsTypeLiteral([ - 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)), - t.tsTypeReference(t.identifier('S')) - ])) - )) - ]) - )) - ]) - ])) + ); + + // Overload 1: with select (autocompletion) + const o1Param = t.identifier('args'); + o1Param.typeAnnotation = t.tsTypeAnnotation( + t.tsIntersectionType([ + argsType(sRef()), + t.tsTypeLiteral([requiredSelectProp()]), + strictSelectGuard(selectTypeName) + ]) ); - const deleteSelectExpr = t.logicalExpression( - '??', + classBody.push(createDeclareMethod('delete', createTypeParam(selectTypeName), [o1Param], retType(sRef()))); + + // Overload 2: without select (default) + const o2Param = t.identifier('args'); + o2Param.typeAnnotation = t.tsTypeAnnotation(withoutSelect(argsType(selectRef()))); + classBody.push(createDeclareMethod('delete', null, [o2Param], retType(defaultRef()))); + + // Implementation + const implParam = t.identifier('args'); + implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef())); + const selectExpr = t.logicalExpression('??', t.memberExpression(t.identifier('args'), t.identifier('select')), - defaultSelectIdent - ); - const deleteArgs = [ + defaultSelectIdent); + const bodyArgs = [ t.stringLiteral(typeName), t.stringLiteral(deleteMutationName), t.stringLiteral(entityLower), @@ -485,10 +644,11 @@ export function generateModelFile( ), t.stringLiteral(deleteInputTypeName), t.stringLiteral(pkField.name), - deleteSelectExpr + selectExpr, + t.identifier('connectionFieldsMap') ]; - classBody.push(createClassMethod('delete', createConstTypeParam(selectTypeName, t.tsTypeQuery(defaultSelectIdent)), [deleteParam], deleteReturnType, - buildMethodBody('buildDeleteByPkDocument', 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)); diff --git a/graphql/codegen/src/core/codegen/orm/select-types.ts b/graphql/codegen/src/core/codegen/orm/select-types.ts index 973b216c3..446a4b642 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,25 @@ 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 * @@ -202,8 +206,9 @@ export interface UpdateArgs { /** * Arguments for delete operations */ -export interface DeleteArgs { +export interface DeleteArgs { where: TWhere; + select?: TSelect; } /** diff --git a/graphql/codegen/src/core/codegen/queries.ts b/graphql/codegen/src/core/codegen/queries.ts index 5e6d7285b..66146e42f 100644 --- a/graphql/codegen/src/core/codegen/queries.ts +++ b/graphql/codegen/src/core/codegen/queries.ts @@ -56,15 +56,23 @@ export function generateListQueryHook( const relationTypeName = `${typeName}WithRelations`; const defaultFieldName = getDefaultSelectFieldName(table); + const listResultType = (s: string) => `{ ${queryName}: ConnectionResult> }`; + const selectionType = (s: string) => `ListSelectionConfig<${s}, ${filterTypeName}, ${orderByTypeName}>`; + const selectionWithFieldsType = (s: string) => + `({ fields: ${s} } & Omit<${selectionType(s)}, 'fields'> & StrictSelect<${s}, ${selectTypeName}>)`; + const selectionWithoutFieldsType = () => + `(Omit<${selectionType(selectTypeName)}, 'fields'> & { fields?: undefined })`; const lines: string[] = []; // Imports if (reactQueryEnabled) { lines.push(`import { useQuery } from '@tanstack/react-query';`); - lines.push(`import type { UseQueryOptions, QueryClient } from '@tanstack/react-query';`); + lines.push(`import type { UseQueryOptions, UseQueryResult, QueryClient } from '@tanstack/react-query';`); } lines.push(`import { getClient } from '../client';`); + lines.push(`import { buildListSelectionArgs } from '../selection';`); + lines.push(`import type { ListSelectionConfig } from '../selection';`); if (useCentralizedKeys) { lines.push(`import { ${keysName} } from '../query-keys';`); @@ -81,9 +89,9 @@ export function generateListQueryHook( lines.push(`} from '../../orm/input-types';`); lines.push(`import type {`); lines.push(` FindManyArgs,`); - lines.push(` DeepExact,`); lines.push(` InferSelectResult,`); lines.push(` ConnectionResult,`); + lines.push(` StrictSelect,`); lines.push(`} from '../../orm/select-types';`); lines.push(''); @@ -99,7 +107,7 @@ export function generateListQueryHook( lines.push(`/** Query key factory - re-exported from query-keys.ts */`); lines.push(`export const ${queryName}QueryKey = ${keysName}.list;`); } else { - lines.push(`export const ${queryName}QueryKey = (variables?: FindManyArgs) => ['${typeName.toLowerCase()}', 'list', variables] as const;`); + lines.push(`export const ${queryName}QueryKey = (variables?: FindManyArgs) => ['${typeName.toLowerCase()}', 'list', variables] as const;`); } lines.push(''); @@ -112,10 +120,12 @@ export function generateListQueryHook( ` * @example`, ` * \`\`\`tsx`, ` * const { data, isLoading } = ${hookName}({`, - ` * select: { id: true, name: true },`, - ` * first: 10,`, - ` * where: { name: { equalTo: "example" } },`, - ` * orderBy: ['CREATED_AT_DESC'],`, + ` * selection: {`, + ` * fields: { id: true, name: true },`, + ` * where: { name: { equalTo: "example" } },`, + ` * orderBy: ['CREATED_AT_DESC'],`, + ` * first: 10,`, + ` * },`, ` * });`, ` * \`\`\`` ]; @@ -123,45 +133,63 @@ 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: { first: 10 },`); + docLines.push(` * scope: { parentId: 'parent-id' },`); + docLines.push(` * });`); docLines.push(` * \`\`\``); } docLines.push(` */`); lines.push(...docLines); - let optionsType: string; - if (hasRelationships && useCentralizedKeys) { - optionsType = `Omit> }, Error>, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }`; - } else { - optionsType = `Omit> }, Error>, 'queryKey' | 'queryFn'>`; - } - - lines.push(`export function ${hookName}(`); - lines.push(` args?: FindManyArgs, ${filterTypeName}, ${orderByTypeName}>,`); - lines.push(` options?: ${optionsType}`); + const optionsType = (queryData: string, data: string) => + hasRelationships && useCentralizedKeys + ? `Omit, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }` + : `Omit, 'queryKey' | 'queryFn'>`; + const implOptionsType = hasRelationships && useCentralizedKeys + ? `Omit, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }` + : `Omit, 'queryKey' | 'queryFn'>`; + + // Overload 1: with selection.fields (autocompletion) + lines.push(`export function ${hookName}(`); + lines.push(` params: { selection: ${selectionWithFieldsType('S')} } & ${optionsType(listResultType('S'), 'TData')}`); + lines.push(`): UseQueryResult;`); + + // Overload 2: no fields (default select) + lines.push(`export function ${hookName}(`); + lines.push(` params?: { selection?: ${selectionWithoutFieldsType()} } & ${optionsType(listResultType('typeof defaultSelect'), 'TData')}`); + lines.push(`): UseQueryResult;`); + + // Implementation + lines.push(`export function ${hookName}(`); + lines.push(` params?: { selection?: ${selectionType(selectTypeName)} } & ${implOptionsType}`); lines.push(`) {`); + lines.push(` const selection = params?.selection;`); + lines.push(` const args = buildListSelectionArgs<${selectTypeName}, ${filterTypeName}, ${orderByTypeName}>(selection);`); if (hasRelationships && useCentralizedKeys) { - lines.push(` const { scope, ...queryOptions } = options ?? {};`); + lines.push(` const { scope, selection: _selection, ...queryOptions } = params ?? {};`); + lines.push(` void _selection;`); lines.push(` return useQuery({`); lines.push(` queryKey: ${keysName}.list(args, scope),`); - lines.push(` queryFn: () => getClient().${singularName}.findMany(args).unwrap(),`); + lines.push(` queryFn: () => getClient().${singularName}.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); lines.push(` ...queryOptions,`); lines.push(` });`); } else if (useCentralizedKeys) { + lines.push(` const { selection: _selection, ...queryOptions } = params ?? {};`); + lines.push(` void _selection;`); lines.push(` return useQuery({`); lines.push(` queryKey: ${keysName}.list(args),`); - lines.push(` queryFn: () => getClient().${singularName}.findMany(args).unwrap(),`); - lines.push(` ...options,`); + lines.push(` queryFn: () => getClient().${singularName}.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); + lines.push(` ...queryOptions,`); lines.push(` });`); } else { + lines.push(` const { selection: _selection, ...queryOptions } = params ?? {};`); + lines.push(` void _selection;`); lines.push(` return useQuery({`); lines.push(` queryKey: ${queryName}QueryKey(args),`); - lines.push(` queryFn: () => getClient().${singularName}.findMany(args).unwrap(),`); - lines.push(` ...options,`); + lines.push(` queryFn: () => getClient().${singularName}.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); + lines.push(` ...queryOptions,`); lines.push(` });`); } @@ -175,13 +203,25 @@ export function generateListQueryHook( lines.push(` *`); lines.push(` * @example`); lines.push(` * \`\`\`ts`); - lines.push(` * const data = await fetch${ucFirst(pluralName)}Query({ first: 10, select: { id: true } });`); + lines.push(` * const data = await fetch${ucFirst(pluralName)}Query({`); + lines.push(` * selection: {`); + lines.push(` * fields: { id: true },`); + lines.push(` * first: 10,`); + lines.push(` * },`); + lines.push(` * });`); lines.push(` * \`\`\``); lines.push(` */`); - lines.push(`export async function fetch${ucFirst(pluralName)}Query(`); - lines.push(` args?: FindManyArgs, ${filterTypeName}, ${orderByTypeName}>,`); + lines.push(`export async function fetch${ucFirst(pluralName)}Query(`); + lines.push(` params: { selection: ${selectionWithFieldsType('S')} }`); + lines.push(`): Promise<${listResultType('S')}>;`); + lines.push(`export async function fetch${ucFirst(pluralName)}Query(`); + lines.push(` params?: { selection?: ${selectionWithoutFieldsType()} }`); + lines.push(`): Promise<${listResultType('typeof defaultSelect')}>;`); + lines.push(`export async function fetch${ucFirst(pluralName)}Query(`); + lines.push(` params?: { selection?: ${selectionType(selectTypeName)} }`); lines.push(`) {`); - lines.push(` return getClient().${singularName}.findMany(args).unwrap();`); + lines.push(` const args = buildListSelectionArgs<${selectTypeName}, ${filterTypeName}, ${orderByTypeName}>(params?.selection);`); + lines.push(` return getClient().${singularName}.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap();`); lines.push(`}`); lines.push(''); @@ -192,31 +232,37 @@ export function generateListQueryHook( lines.push(` *`); lines.push(` * @example`); lines.push(` * \`\`\`ts`); - lines.push(` * await prefetch${ucFirst(pluralName)}Query(queryClient, { first: 10 });`); + lines.push(` * await prefetch${ucFirst(pluralName)}Query(queryClient, { selection: { first: 10 } });`); lines.push(` * \`\`\``); lines.push(` */`); - lines.push(`export async function prefetch${ucFirst(pluralName)}Query(`); + lines.push(`export async function prefetch${ucFirst(pluralName)}Query(`); lines.push(` queryClient: QueryClient,`); - lines.push(` args?: FindManyArgs, ${filterTypeName}, ${orderByTypeName}>,`); - if (hasRelationships && useCentralizedKeys) { - lines.push(` scope?: ${scopeTypeName},`); - } + lines.push(` params: { selection: ${selectionWithFieldsType('S')} }${hasRelationships && useCentralizedKeys ? ` & { scope?: ${scopeTypeName} }` : ''}`); + lines.push(`): Promise;`); + lines.push(`export async function prefetch${ucFirst(pluralName)}Query(`); + lines.push(` queryClient: QueryClient,`); + lines.push(` params?: { selection?: ${selectionWithoutFieldsType()} }${hasRelationships && useCentralizedKeys ? ` & { scope?: ${scopeTypeName} }` : ''}`); + lines.push(`): Promise;`); + lines.push(`export async function prefetch${ucFirst(pluralName)}Query(`); + lines.push(` queryClient: QueryClient,`); + lines.push(` params?: { selection?: ${selectionType(selectTypeName)} }${hasRelationships && useCentralizedKeys ? ` & { scope?: ${scopeTypeName} }` : ''}`); lines.push(`): Promise {`); + lines.push(` const args = buildListSelectionArgs<${selectTypeName}, ${filterTypeName}, ${orderByTypeName}>(params?.selection);`); if (hasRelationships && useCentralizedKeys) { lines.push(` await queryClient.prefetchQuery({`); - lines.push(` queryKey: ${keysName}.list(args, scope),`); - lines.push(` queryFn: () => getClient().${singularName}.findMany(args).unwrap(),`); + lines.push(` queryKey: ${keysName}.list(args, params?.scope),`); + lines.push(` queryFn: () => getClient().${singularName}.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); lines.push(` });`); } else if (useCentralizedKeys) { lines.push(` await queryClient.prefetchQuery({`); lines.push(` queryKey: ${keysName}.list(args),`); - lines.push(` queryFn: () => getClient().${singularName}.findMany(args).unwrap(),`); + lines.push(` queryFn: () => getClient().${singularName}.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); lines.push(` });`); } else { lines.push(` await queryClient.prefetchQuery({`); lines.push(` queryKey: ${queryName}QueryKey(args),`); - lines.push(` queryFn: () => getClient().${singularName}.findMany(args).unwrap(),`); + lines.push(` queryFn: () => getClient().${singularName}.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); lines.push(` });`); } @@ -260,15 +306,21 @@ export function generateSingleQueryHook( const pkFieldName = pkField?.name ?? 'id'; const pkFieldTsType = pkField?.tsType ?? 'string'; const defaultFieldName = getDefaultSelectFieldName(table); + const singleResultType = (s: string) => `{ ${queryName}: InferSelectResult<${relationTypeName}, ${s}> | null }`; + const selectionWithFieldsType = (s: string) => + `({ fields: ${s} } & StrictSelect<${s}, ${selectTypeName}>)`; + const selectionWithoutFieldsType = () => `({ fields?: undefined })`; const lines: string[] = []; // Imports if (reactQueryEnabled) { lines.push(`import { useQuery } from '@tanstack/react-query';`); - lines.push(`import type { UseQueryOptions, QueryClient } from '@tanstack/react-query';`); + lines.push(`import type { UseQueryOptions, UseQueryResult, QueryClient } from '@tanstack/react-query';`); } lines.push(`import { getClient } from '../client';`); + lines.push(`import { buildSelectionArgs } from '../selection';`); + lines.push(`import type { SelectionConfig } from '../selection';`); if (useCentralizedKeys) { lines.push(`import { ${keysName} } from '../query-keys';`); @@ -282,8 +334,8 @@ export function generateSingleQueryHook( lines.push(` ${relationTypeName},`); lines.push(`} from '../../orm/input-types';`); lines.push(`import type {`); - lines.push(` DeepExact,`); lines.push(` InferSelectResult,`); + lines.push(` StrictSelect,`); lines.push(`} from '../../orm/select-types';`); lines.push(''); @@ -313,7 +365,7 @@ export function generateSingleQueryHook( ` * \`\`\`tsx`, ` * const { data, isLoading } = ${hookName}({`, ` * ${pkFieldName}: 'some-id',`, - ` * select: { id: true, name: true },`, + ` * selection: { fields: { id: true, name: true } },`, ` * });`, ` * \`\`\`` ]; @@ -321,45 +373,62 @@ export function generateSingleQueryHook( docLines.push(` *`); docLines.push(` * @example With scope for hierarchical cache invalidation`); docLines.push(` * \`\`\`tsx`); - docLines.push(` * const { data } = ${hookName}(`); - docLines.push(` * { ${pkFieldName}: 'some-id' },`); - docLines.push(` * { scope: { parentId: 'parent-id' } }`); - docLines.push(` * );`); + docLines.push(` * const { data } = ${hookName}({`); + docLines.push(` * ${pkFieldName}: 'some-id',`); + docLines.push(` * scope: { parentId: 'parent-id' },`); + docLines.push(` * });`); docLines.push(` * \`\`\``); } docLines.push(` */`); lines.push(...docLines); - let optionsType: string; - if (hasRelationships && useCentralizedKeys) { - optionsType = `Omit | null }, Error>, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }`; - } else { - optionsType = `Omit | null }, Error>, 'queryKey' | 'queryFn'>`; - } - - lines.push(`export function ${hookName}(`); - lines.push(` args: { ${pkFieldName}: ${pkFieldTsType}; select?: DeepExact },`); - lines.push(` options?: ${optionsType}`); + const singleOptionsType = (queryData: string, data: string) => + hasRelationships && useCentralizedKeys + ? `Omit, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }` + : `Omit, 'queryKey' | 'queryFn'>`; + const singleImplOptionsType = hasRelationships && useCentralizedKeys + ? `Omit, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }` + : `Omit, 'queryKey' | 'queryFn'>`; + + // Overload 1: with selection.fields (provides contextual typing for autocompletion) + lines.push(`export function ${hookName}(`); + lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection: ${selectionWithFieldsType('S')} } & ${singleOptionsType(singleResultType('S'), 'TData')}`); + lines.push(`): UseQueryResult;`); + + // Overload 2: without fields (uses default select) + lines.push(`export function ${hookName}(`); + lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection?: ${selectionWithoutFieldsType()} } & ${singleOptionsType(singleResultType('typeof defaultSelect'), 'TData')}`); + lines.push(`): UseQueryResult;`); + + // Implementation + lines.push(`export function ${hookName}(`); + lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection?: SelectionConfig<${selectTypeName}> } & ${singleImplOptionsType}`); lines.push(`) {`); + lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params.selection);`); if (hasRelationships && useCentralizedKeys) { - lines.push(` const { scope, ...queryOptions } = options ?? {};`); + lines.push(` const { scope, selection: _selection, ...queryOptions } = params ?? {};`); + lines.push(` void _selection;`); lines.push(` return useQuery({`); - lines.push(` queryKey: ${keysName}.detail(args.${pkFieldName}, scope),`); - lines.push(` queryFn: () => getClient().${singularName}.findOne(args).unwrap(),`); + lines.push(` queryKey: ${keysName}.detail(params.${pkFieldName}, scope),`); + lines.push(` queryFn: () => getClient().${singularName}.findOne({ ${pkFieldName}: params.${pkFieldName}, ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); lines.push(` ...queryOptions,`); lines.push(` });`); } else if (useCentralizedKeys) { + lines.push(` const { selection: _selection, ...queryOptions } = params ?? {};`); + lines.push(` void _selection;`); lines.push(` return useQuery({`); - lines.push(` queryKey: ${keysName}.detail(args.${pkFieldName}),`); - lines.push(` queryFn: () => getClient().${singularName}.findOne(args).unwrap(),`); - lines.push(` ...options,`); + lines.push(` queryKey: ${keysName}.detail(params.${pkFieldName}),`); + lines.push(` queryFn: () => getClient().${singularName}.findOne({ ${pkFieldName}: params.${pkFieldName}, ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); + lines.push(` ...queryOptions,`); lines.push(` });`); } else { + lines.push(` const { selection: _selection, ...queryOptions } = params ?? {};`); + lines.push(` void _selection;`); lines.push(` return useQuery({`); - lines.push(` queryKey: ${queryName}QueryKey(args.${pkFieldName}),`); - lines.push(` queryFn: () => getClient().${singularName}.findOne(args).unwrap(),`); - lines.push(` ...options,`); + lines.push(` queryKey: ${queryName}QueryKey(params.${pkFieldName}),`); + lines.push(` queryFn: () => getClient().${singularName}.findOne({ ${pkFieldName}: params.${pkFieldName}, ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); + lines.push(` ...queryOptions,`); lines.push(` });`); } @@ -373,13 +442,23 @@ export function generateSingleQueryHook( lines.push(` *`); lines.push(` * @example`); lines.push(` * \`\`\`ts`); - lines.push(` * const data = await fetch${ucFirst(singularName)}Query({ ${pkFieldName}: 'some-id', select: { id: true } });`); + lines.push(` * const data = await fetch${ucFirst(singularName)}Query({`); + lines.push(` * ${pkFieldName}: 'some-id',`); + lines.push(` * selection: { fields: { id: true } },`); + lines.push(` * });`); lines.push(` * \`\`\``); lines.push(` */`); - lines.push(`export async function fetch${ucFirst(singularName)}Query(`); - lines.push(` args: { ${pkFieldName}: ${pkFieldTsType}; select?: DeepExact },`); + lines.push(`export async function fetch${ucFirst(singularName)}Query(`); + lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection: ${selectionWithFieldsType('S')} }`); + lines.push(`): Promise<${singleResultType('S')}>;`); + lines.push(`export async function fetch${ucFirst(singularName)}Query(`); + lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection?: ${selectionWithoutFieldsType()} },`); + lines.push(`): Promise<${singleResultType('typeof defaultSelect')}>;`); + lines.push(`export async function fetch${ucFirst(singularName)}Query(`); + lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection?: SelectionConfig<${selectTypeName}> },`); lines.push(`) {`); - lines.push(` return getClient().${singularName}.findOne(args).unwrap();`); + lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params.selection);`); + lines.push(` return getClient().${singularName}.findOne({ ${pkFieldName}: params.${pkFieldName}, ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap();`); lines.push(`}`); lines.push(''); @@ -393,28 +472,37 @@ export function generateSingleQueryHook( lines.push(` * await prefetch${ucFirst(singularName)}Query(queryClient, { ${pkFieldName}: 'some-id' });`); lines.push(` * \`\`\``); lines.push(` */`); - lines.push(`export async function prefetch${ucFirst(singularName)}Query(`); + lines.push(`export async function prefetch${ucFirst(singularName)}Query(`); lines.push(` queryClient: QueryClient,`); - lines.push(` args: { ${pkFieldName}: ${pkFieldTsType}; select?: DeepExact },`); + lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection: ${selectionWithFieldsType('S')} }${hasRelationships && useCentralizedKeys ? ` & { scope?: ${scopeTypeName} }` : ''},`); if (hasRelationships && useCentralizedKeys) { - lines.push(` scope?: ${scopeTypeName},`); + // scope is included in params above } + lines.push(`): Promise;`); + lines.push(`export async function prefetch${ucFirst(singularName)}Query(`); + lines.push(` queryClient: QueryClient,`); + lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection?: ${selectionWithoutFieldsType()} }${hasRelationships && useCentralizedKeys ? ` & { scope?: ${scopeTypeName} }` : ''},`); + lines.push(`): Promise;`); + lines.push(`export async function prefetch${ucFirst(singularName)}Query(`); + lines.push(` queryClient: QueryClient,`); + lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection?: SelectionConfig<${selectTypeName}> }${hasRelationships && useCentralizedKeys ? ` & { scope?: ${scopeTypeName} }` : ''},`); lines.push(`): Promise {`); + lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params.selection);`); if (hasRelationships && useCentralizedKeys) { lines.push(` await queryClient.prefetchQuery({`); - lines.push(` queryKey: ${keysName}.detail(args.${pkFieldName}, scope),`); - lines.push(` queryFn: () => getClient().${singularName}.findOne(args).unwrap(),`); + lines.push(` queryKey: ${keysName}.detail(params.${pkFieldName}, params.scope),`); + lines.push(` queryFn: () => getClient().${singularName}.findOne({ ${pkFieldName}: params.${pkFieldName}, ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); lines.push(` });`); } else if (useCentralizedKeys) { lines.push(` await queryClient.prefetchQuery({`); - lines.push(` queryKey: ${keysName}.detail(args.${pkFieldName}),`); - lines.push(` queryFn: () => getClient().${singularName}.findOne(args).unwrap(),`); + lines.push(` queryKey: ${keysName}.detail(params.${pkFieldName}),`); + lines.push(` queryFn: () => getClient().${singularName}.findOne({ ${pkFieldName}: params.${pkFieldName}, ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); lines.push(` });`); } else { lines.push(` await queryClient.prefetchQuery({`); - lines.push(` queryKey: ${queryName}QueryKey(args.${pkFieldName}),`); - lines.push(` queryFn: () => getClient().${singularName}.findOne(args).unwrap(),`); + lines.push(` queryKey: ${queryName}QueryKey(params.${pkFieldName}),`); + lines.push(` queryFn: () => getClient().${singularName}.findOne({ ${pkFieldName}: params.${pkFieldName}, ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); lines.push(` });`); } diff --git a/graphql/codegen/src/core/codegen/select-helpers.ts b/graphql/codegen/src/core/codegen/select-helpers.ts index d17a770e3..4ae52a351 100644 --- a/graphql/codegen/src/core/codegen/select-helpers.ts +++ b/graphql/codegen/src/core/codegen/select-helpers.ts @@ -37,17 +37,18 @@ export function getSelectTypeName(returnType: CleanArgument['type']): string | n */ export function wrapInferSelectResult( typeRef: CleanArgument['type'], - payloadTypeName: string + payloadTypeName: string, + selectType: string = 'S' ): string { if (typeRef.kind === 'NON_NULL' && typeRef.ofType) { - return wrapInferSelectResult(typeRef.ofType as CleanArgument['type'], payloadTypeName); + return wrapInferSelectResult(typeRef.ofType as CleanArgument['type'], payloadTypeName, selectType); } if (typeRef.kind === 'LIST' && typeRef.ofType) { - return `${wrapInferSelectResult(typeRef.ofType as CleanArgument['type'], payloadTypeName)}[]`; + return `${wrapInferSelectResult(typeRef.ofType as CleanArgument['type'], payloadTypeName, selectType)}[]`; } - return `InferSelectResult<${payloadTypeName}, S>`; + 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..e205f3ca4 --- /dev/null +++ b/graphql/codegen/src/core/codegen/selection.ts @@ -0,0 +1,87 @@ +/** + * Selection helper generator for React Query hooks + * + * Generates selection.ts as a shared adapter layer between hook-facing + * `selection` params and ORM-facing args (`select`, `where`, `orderBy`, etc.). + */ +import { getGeneratedFileHeader } from './utils'; + +/** + * Generate selection.ts content - shared selection types + runtime mappers + */ +export function generateSelectionFile(): string { + const header = getGeneratedFileHeader('Selection helpers for React Query hooks'); + + const code = ` +export interface SelectionConfig { + fields?: TFields; +} + +export interface ListSelectionConfig + extends SelectionConfig { + where?: TWhere; + orderBy?: TOrderBy[]; + first?: number; + last?: number; + after?: string; + before?: string; + offset?: number; +} + +export function buildSelectionArgs( + selection?: SelectionConfig +): { select?: TFields } | undefined { + if (!selection || selection.fields === undefined) { + return undefined; + } + + 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; + } + | undefined { + if (!selection) { + return undefined; + } + + const hasAnyValues = + selection.fields !== undefined || + selection.where !== undefined || + selection.orderBy !== undefined || + selection.first !== undefined || + selection.last !== undefined || + selection.after !== undefined || + selection.before !== undefined || + selection.offset !== undefined; + + if (!hasAnyValues) { + return undefined; + } + + 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 + }; +} +`; + + return header + '\n\n' + code.trim() + '\n'; +} diff --git a/graphql/codegen/src/core/codegen/templates/query-builder.ts b/graphql/codegen/src/core/codegen/templates/query-builder.ts index a678fbbd0..a62cdf075 100644 --- a/graphql/codegen/src/core/codegen/templates/query-builder.ts +++ b/graphql/codegen/src/core/codegen/templates/query-builder.ts @@ -96,13 +96,16 @@ 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) { @@ -124,11 +127,13 @@ 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 @@ -181,10 +186,11 @@ 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[] = []; @@ -267,10 +273,11 @@ 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[] = []; @@ -326,10 +333,11 @@ 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 { @@ -359,10 +367,11 @@ export function buildUpdateDocument> ): { document: string; variables: Record } { const selections = select - ? buildSelections(select as Record) + ? buildSelections(select as Record, connectionFieldsMap, operationName) : [t.field({ name: 'id' })]; return { @@ -394,10 +403,11 @@ export function buildUpdateByPkDocument( id: string | number, data: TData, inputTypeName: string, - idFieldName: string + idFieldName: 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 { @@ -427,10 +437,11 @@ export function buildFindOneDocument( id: string | number, select: TSelect, idArgName: string, - idTypeName: string + idTypeName: 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[] = [ @@ -478,10 +489,11 @@ export function buildDeleteDocument> ): { document: string; variables: Record } { const entitySelections = select - ? buildSelections(select as Record) + ? buildSelections(select as Record, connectionFieldsMap, operationName) : [t.field({ name: 'id' })]; return { @@ -513,10 +525,11 @@ export function buildDeleteByPkDocument( id: string | number, inputTypeName: string, idFieldName: string, - select?: TSelect + select?: TSelect, + connectionFieldsMap?: Record> ): { document: string; variables: Record } { const entitySelections = select - ? buildSelections(select as Record) + ? buildSelections(select as Record, connectionFieldsMap, operationName) : [t.field({ name: 'id' })]; return { @@ -545,7 +558,9 @@ export function buildCustomDocument( 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; @@ -559,7 +574,7 @@ export function buildCustomDocument( } const selections = actualSelect - ? buildSelections(actualSelect as Record) + ? buildSelections(actualSelect as Record, connectionFieldsMap, entityType) : []; const variableDefs = variableDefinitions.map((definition) => diff --git a/graphql/codegen/src/core/codegen/templates/select-types.ts b/graphql/codegen/src/core/codegen/templates/select-types.ts index df14aac7b..5656e4901 100644 --- a/graphql/codegen/src/core/codegen/templates/select-types.ts +++ b/graphql/codegen/src/core/codegen/templates/select-types.ts @@ -64,16 +64,10 @@ export interface DeleteArgs { /** * 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: @@ -90,15 +84,25 @@ 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 */ From 4fac2c18346c9cd24a6d6fb213b4ef29d21854e8 Mon Sep 17 00:00:00 2001 From: yyyyaaa Date: Sat, 7 Feb 2026 14:33:01 +0700 Subject: [PATCH 03/17] fix(codegen-cli): honor source flags and config overrides --- graphql/codegen/src/cli/index.ts | 77 ++++++++++++++++++++-- graphql/codegen/src/cli/shared.ts | 2 +- graphql/codegen/src/core/generate.ts | 7 ++ graphql/codegen/src/types/config.ts | 7 +- packages/cli/__tests__/codegen.test.ts | 2 + packages/cli/src/commands/codegen.ts | 91 ++++++++++++++++++++++++-- 6 files changed, 168 insertions(+), 18 deletions(-) diff --git a/graphql/codegen/src/cli/index.ts b/graphql/codegen/src/cli/index.ts index 6698e2a38..ad499af48 100644 --- a/graphql/codegen/src/cli/index.ts +++ b/graphql/codegen/src/cli/index.ts @@ -10,7 +10,13 @@ import { CLI, CLIOptions, getPackageJson,Inquirerer } from 'inquirerer'; import { findConfigFile, loadConfigFile } from '../core/config'; import { generate } from '../core/generate'; import type { GraphQLSDKConfigTarget } from '../types/config'; -import { camelizeArgv, type CodegenAnswers,codegenQuestions, printResult } from './shared'; +import { + camelizeArgv, + type CodegenAnswers, + codegenQuestions, + printResult, + splitCommas +} from './shared'; const usage = ` graphql-codegen - GraphQL SDK generator for Constructive databases @@ -33,8 +39,7 @@ 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 + --browser-compatible Deprecated no-op (retained for compatibility) --dry-run Preview without writing files -v, --verbose Show detailed output @@ -58,15 +63,46 @@ export const commands = async ( process.exit(0); } - const configPath = (argv.config || argv.c || findConfigFile()) as string | undefined; + const hasSourceCliFlags = 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 autoConfigPath = !explicitConfigPath && !hasSourceCliFlags + ? findConfigFile() + : undefined; + const configPath = (explicitConfigPath || autoConfigPath) as string | undefined; const targetName = (argv.target || argv.t) as string | undefined; // Collect CLI flags that should override config file settings const cliOverrides: Partial = {}; - if (argv['react-query'] === true) cliOverrides.reactQuery = true; + const endpoint = (argv.endpoint || argv.e) as string | undefined; + const schemaFile = (argv['schema-file'] || argv.s) as string | undefined; + const schemas = splitCommas(argv.schemas as string | undefined); + const apiNames = splitCommas(argv['api-names'] as string | undefined); + if (endpoint) { + cliOverrides.endpoint = endpoint; + cliOverrides.schemaFile = undefined; + cliOverrides.db = undefined; + } + if (schemaFile) { + cliOverrides.schemaFile = schemaFile; + cliOverrides.endpoint = undefined; + cliOverrides.db = undefined; + } + if (schemas || apiNames) { + cliOverrides.db = { schemas, apiNames }; + cliOverrides.endpoint = undefined; + cliOverrides.schemaFile = undefined; + } + if (argv['react-query'] === true || argv.reactQuery === true) cliOverrides.reactQuery = true; if (argv.orm === true) cliOverrides.orm = true; if (argv.verbose === true || argv.v === true) cliOverrides.verbose = true; - if (argv['dry-run'] === true) cliOverrides.dryRun = true; + if (argv['dry-run'] === true || argv.dryRun === true) cliOverrides.dryRun = true; if (argv.output || argv.o) cliOverrides.output = (argv.output || argv.o) as string; if (argv.authorization || argv.a) cliOverrides.authorization = (argv.authorization || argv.a) as string; @@ -114,6 +150,35 @@ export const commands = async ( return argv; } + const hasNonInteractiveArgs = Boolean( + endpoint || + schemaFile || + schemas || + apiNames || + argv['react-query'] === true || + argv.reactQuery === true || + argv.orm === true || + argv.output || + argv.o || + argv.authorization || + argv.a || + argv['dry-run'] === true || + argv.dryRun === true || + argv.verbose === true || + argv.v === true || + argv['browser-compatible'] !== undefined || + argv.browserCompatible !== undefined + ); + + if (hasNonInteractiveArgs) { + const result = await generate({ + ...cliOverrides + }); + printResult(result); + prompter.close(); + return argv; + } + // No config file - prompt for options using shared questions const answers = await prompter.prompt(argv as CodegenAnswers, codegenQuestions); diff --git a/graphql/codegen/src/cli/shared.ts b/graphql/codegen/src/cli/shared.ts index a1dee66a5..87a55bac9 100644 --- a/graphql/codegen/src/cli/shared.ts +++ b/graphql/codegen/src/cli/shared.ts @@ -92,7 +92,7 @@ export const codegenQuestions: Question[] = [ }, { name: 'browser-compatible', - message: 'Generate browser-compatible code?', + message: 'Browser-compatible mode (deprecated no-op)?', type: 'confirm', required: false, default: true, diff --git a/graphql/codegen/src/core/generate.ts b/graphql/codegen/src/core/generate.ts index e73b34edc..f3f63b948 100644 --- a/graphql/codegen/src/core/generate.ts +++ b/graphql/codegen/src/core/generate.ts @@ -43,6 +43,13 @@ export async function generate(options: GenerateOptions = {}): Promise { 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 }, diff --git a/packages/cli/src/commands/codegen.ts b/packages/cli/src/commands/codegen.ts index 0d41bccae..d532b946f 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, + splitCommas, type CodegenAnswers, + type GraphQLSDKConfigTarget, } from '@constructive-io/graphql-codegen'; const usage = ` @@ -27,8 +30,7 @@ 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 + --browser-compatible Deprecated no-op (retained for compatibility) --dry-run Preview without writing files --verbose Verbose output @@ -45,11 +47,86 @@ 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({}); + const hasSourceCliFlags = Boolean( + argv.endpoint || + argv['schema-file'] || + argv.schemaFile || + argv.schemas || + argv['api-names'] || + argv.apiNames + ); + const explicitConfigPath = argv.config as string | undefined; + const autoConfigPath = !explicitConfigPath && !hasSourceCliFlags + ? findConfigFile() + : undefined; + const configPath = explicitConfigPath || autoConfigPath; + + const endpoint = argv.endpoint as string | undefined; + const schemaFile = (argv['schema-file'] || argv.schemaFile) as string | undefined; + const schemas = splitCommas(argv.schemas as string | undefined); + const apiNames = splitCommas((argv['api-names'] || argv.apiNames) as string | undefined); + + const cliOverrides: Partial = {}; + if (endpoint) { + cliOverrides.endpoint = endpoint; + cliOverrides.schemaFile = undefined; + cliOverrides.db = undefined; + } + if (schemaFile) { + cliOverrides.schemaFile = schemaFile; + cliOverrides.endpoint = undefined; + cliOverrides.db = undefined; + } + if (schemas || apiNames) { + cliOverrides.db = { schemas, apiNames }; + cliOverrides.endpoint = undefined; + cliOverrides.schemaFile = undefined; + } + if (argv['react-query'] === true || argv.reactQuery === true) cliOverrides.reactQuery = true; + if (argv.orm === true) cliOverrides.orm = true; + if (argv.verbose === true) cliOverrides.verbose = true; + if (argv['dry-run'] === true || argv.dryRun === true) cliOverrides.dryRun = true; + if (argv.output) cliOverrides.output = argv.output as string; + if (argv.authorization) cliOverrides.authorization = argv.authorization as string; + if (argv['browser-compatible'] !== undefined) { + cliOverrides.browserCompatible = argv['browser-compatible'] as boolean; + } else if (argv.browserCompatible !== undefined) { + cliOverrides.browserCompatible = argv.browserCompatible as boolean; + } + + if (configPath) { + const loaded = await loadConfigFile(configPath); + if (!loaded.success) { + console.error('x', loaded.error); + process.exit(1); + } + const result = await generate({ + ...(loaded.config as GraphQLSDKConfigTarget), + ...cliOverrides, + }); + printResult(result); + return; + } + + const hasNonInteractiveArgs = Boolean( + endpoint || + schemaFile || + schemas || + apiNames || + argv['react-query'] === true || + argv.reactQuery === true || + argv.orm === true || + argv.output || + argv.authorization || + argv['dry-run'] === true || + argv.dryRun === true || + argv.verbose === true || + argv['browser-compatible'] !== undefined || + argv.browserCompatible !== undefined + ); + + if (hasNonInteractiveArgs) { + const result = await generate({ ...cliOverrides }); printResult(result); return; } From 3639dc4286dc6b6aeb499c1c436186485960a05c Mon Sep 17 00:00:00 2001 From: yyyyaaa Date: Sat, 7 Feb 2026 14:35:08 +0700 Subject: [PATCH 04/17] feat(test-codegen-app): add local codegen validation app --- graphql/test-app/.gitignore | 1 + graphql/test-app/README.md | 62 + graphql/test-app/codegen.config.ts | 9 + graphql/test-app/index.html | 12 + graphql/test-app/package.json | 39 + graphql/test-app/scripts/analyze-bundle.ts | 155 + graphql/test-app/src/App.tsx | 1034 ++ graphql/test-app/src/main.tsx | 28 + .../react-query-helpers-options.type-test.ts | 266 + .../react-query-orm-overloads.type-test.ts | 306 + ...select-strictness-regressions.type-test.ts | 200 + graphql/test-app/src/vite-env.d.ts | 1 + graphql/test-app/tests/hook-test-utils.ts | 85 + graphql/test-app/tests/hooks.live.test.ts | 341 + graphql/test-app/tests/live-test-utils.ts | 130 + graphql/test-app/tests/orm.live.test.ts | 232 + graphql/test-app/tsconfig.json | 18 + graphql/test-app/vite.config.ts | 19 + pnpm-lock.yaml | 10233 +++++----------- 19 files changed, 6153 insertions(+), 7018 deletions(-) create mode 100644 graphql/test-app/.gitignore create mode 100644 graphql/test-app/README.md create mode 100644 graphql/test-app/codegen.config.ts create mode 100644 graphql/test-app/index.html create mode 100644 graphql/test-app/package.json create mode 100644 graphql/test-app/scripts/analyze-bundle.ts create mode 100644 graphql/test-app/src/App.tsx create mode 100644 graphql/test-app/src/main.tsx create mode 100644 graphql/test-app/src/type-tests/react-query-helpers-options.type-test.ts create mode 100644 graphql/test-app/src/type-tests/react-query-orm-overloads.type-test.ts create mode 100644 graphql/test-app/src/type-tests/select-strictness-regressions.type-test.ts create mode 100644 graphql/test-app/src/vite-env.d.ts create mode 100644 graphql/test-app/tests/hook-test-utils.ts create mode 100644 graphql/test-app/tests/hooks.live.test.ts create mode 100644 graphql/test-app/tests/live-test-utils.ts create mode 100644 graphql/test-app/tests/orm.live.test.ts create mode 100644 graphql/test-app/tsconfig.json create mode 100644 graphql/test-app/vite.config.ts 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..9daf7e78f --- /dev/null +++ b/graphql/test-app/codegen.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from '@constructive-io/graphql-codegen'; + +const config = defineConfig({ + endpoint: 'https://api.launchql.dev/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..139ad00f0 --- /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": "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..2c4498806 --- /dev/null +++ b/graphql/test-app/src/App.tsx @@ -0,0 +1,1034 @@ +/** + * 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({ + 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..3728e01d0 --- /dev/null +++ b/graphql/test-app/src/type-tests/react-query-helpers-options.type-test.ts @@ -0,0 +1,266 @@ +/** + * Compile-time regression checks for helper overloads and React Query options. + * + * Focus: + * - fetch/prefetch overload behavior + * - optional variables + required selection.fields custom query overloads + * - default vs explicit selection result narrowing in helpers + * - allowed/disallowed React Query options on generated hooks + */ + +import { QueryClient } from '@tanstack/react-query'; + +import { + fetchDatabasesQuery, + fetchGetObjectAtPathQuery, + prefetchDatabasesQuery, + prefetchGetObjectAtPathQuery, + useCurrentUserQuery, + useDatabasesQuery, + useGetObjectAtPathQuery, + useSignInMutation, +} 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 defaultDatabasesFetch = fetchDatabasesQuery({ selection: { first: 2 } }); + type DefaultDatabaseNode = Awaited['databases']['nodes'][number]; + type _defaultDatabaseFetchOmitsName = Assert>; + + const selectedDatabasesFetch = fetchDatabasesQuery({ + selection: { + first: 2, + fields: { + id: true, + name: true, + schemas: { + first: 1, + select: { + id: true, + schemaName: true, + }, + }, + }, + }, + }); + type SelectedDatabaseNode = Awaited['databases']['nodes'][number]; + type _selectedDatabaseFetchHasName = Assert>; + + prefetchDatabasesQuery(queryClient, { selection: { first: 2 } }); + prefetchDatabasesQuery(queryClient, { + selection: { + first: 2, + fields: { + id: true, + name: true, + }, + }, + }); + + // @ts-expect-error invalid helper nested select key should be rejected + fetchDatabasesQuery({ selection: { fields: { schemas: { select: { invalidField: true } } } } }); + + const defaultGetObjectFetch = fetchGetObjectAtPathQuery({ variables: undefined }); + type DefaultGetObject = Awaited['getObjectAtPath']; + type _defaultGetObjectOmitsData = Assert>; + + const selectedGetObjectFetch = fetchGetObjectAtPathQuery({ + variables: undefined, + selection: { + fields: { + id: true, + data: true, + }, + }, + }); + type SelectedGetObject = Awaited['getObjectAtPath']; + type _selectedGetObjectHasData = Assert>; + + prefetchGetObjectAtPathQuery(queryClient, { variables: undefined }); + prefetchGetObjectAtPathQuery(queryClient, { + variables: undefined, + selection: { + fields: { + id: true, + }, + }, + }); + + // @ts-expect-error invalid custom helper select key should be rejected + prefetchGetObjectAtPathQuery(queryClient, { + variables: undefined, + selection: { fields: { invalidField: true } }, + }); + + // @ts-expect-error custom helper select overload requires explicit variables + fetchGetObjectAtPathQuery({ selection: { fields: { id: true } } }); + + // @ts-expect-error custom helper prefetch overload requires explicit variables + prefetchGetObjectAtPathQuery(queryClient, { 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 transformedCurrentUser = useCurrentUserQuery({ + select: (data) => data.currentUser.id, + placeholderData: (previousData) => + previousData ?? { + currentUser: { + id: 'fallback-user-id', + }, + }, + enabled: false, + staleTime: 5_000, + gcTime: 60_000, + retry: (failureCount, error) => { + const msg = error.message; + void msg; + return failureCount < 2; + }, + }); + const transformedCurrentUserId: string | undefined = transformedCurrentUser.data; + void transformedCurrentUserId; + // @ts-expect-error transformed query data should not expose object shape + transformedCurrentUser.data.currentUser; + + useGetObjectAtPathQuery({ + variables: undefined, + selection: { + fields: { + id: true, + }, + }, + enabled: false, + staleTime: 5_000, + gcTime: 60_000, + placeholderData: { + getObjectAtPath: { + id: 'placeholder', + }, + }, + select: (data) => data.getObjectAtPath.id, + }); + + // @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 }); + + // @ts-expect-error queryFn is owned by generated hooks + useDatabasesQuery({ + selection: { fields: { id: true } }, + queryFn: async () => + ({ + databases: { + nodes: [], + totalCount: 0, + pageInfo: { + hasNextPage: false, + hasPreviousPage: false, + }, + }, + }) as never, + }); + + useSignInMutation({ + selection: { + fields: { + clientMutationId: 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 clientMutationId = data.signIn.clientMutationId; + const email = variables.input.email; + void clientMutationId; + void email; + }, + }); + + // @ts-expect-error mutationFn is owned by generated hooks + useSignInMutation({ + selection: { fields: { clientMutationId: true } }, + 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..c44f21281 --- /dev/null +++ b/graphql/test-app/src/type-tests/react-query-orm-overloads.type-test.ts @@ -0,0 +1,306 @@ +/** + * Compile-time regression checks for React Query + ORM output modes. + * + * These checks focus on overload behavior introduced to recover contextual + * typing/autocomplete for nested select objects. + */ + +import { + useCurrentUserQuery, + useGetObjectAtPathQuery, + useSignInMutation, + 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; + + const defaultUser = useUserQuery({ id: '00000000-0000-0000-0000-000000000000' }); + const defaultUserId = defaultUser.data?.user?.id; + void defaultUserId; + // @ts-expect-error default select for useUserQuery should not expose username + defaultUser.data?.user?.username; + + 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, + databasesByOwnerId: { + first: 2, + select: { + id: true, + schemaName: true, + name: true + }, + }, + }, + first: 5, + orderBy: ['CREATED_AT_DESC'], + }, + }); + + const nestedSchema = users.data?.users.nodes[0]?.databasesByOwnerId?.nodes[0]?.schemaName; + void nestedSchema; + + // Optional variables + required select args overload (custom query case) + useGetObjectAtPathQuery({ + variables: undefined, + selection: { + fields: { + id: true, + data: true, + }, + }, + }); + + const defaultSignIn = useSignInMutation(); + const defaultSignInClientMutationId = defaultSignIn.data?.signIn.clientMutationId; + void defaultSignInClientMutationId; + // @ts-expect-error default signIn select should not expose result + defaultSignIn.data?.signIn.result; + + 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 = { + databasesByOwnerId: { + 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 } }); + + // @ts-expect-error invalid nested select key should be rejected + useUsersQuery({ + selection: { + fields: { + databasesByOwnerId: { + select: { + doesNotExist: true, + }, + }, + }, + }, + }); + + // @ts-expect-error invalid custom query select key should be rejected + useGetObjectAtPathQuery({ + variables: undefined, + selection: { fields: { nope: true } }, + }); +} + +async function ormModelTypeChecks() { + const defaultBuilder = ormClient.user.findOne({ + id: '00000000-0000-0000-0000-000000000000', + }); + type DefaultUser = Awaited>['user']; + type _defaultOmitsUsername = Assert, 'username'>>; + + const defaultSelected = await defaultBuilder.unwrapOr({ user: null }); + + if (defaultSelected.user) { + const id: string = defaultSelected.user.id; + void id; + } + + const explicitlySelected = ormClient.user.findOne({ + id: '00000000-0000-0000-0000-000000000000', + select: { + id: true, + username: true, + databasesByOwnerId: { + 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, + databasesByOwnerId: { + first: 1, + select: { + id: true, + schemaName: true, + }, + }, + }, + }); + + ormClient.query.currentUser({ + select: { + id: true, + username: true, + databasesByOwnerId: { + first: 1, + select: { + id: true, + }, + }, + }, + }); + + ormClient.query.getObjectAtPath( + { + dbId: '00000000-0000-0000-0000-000000000000', + path: ['root'], + refname: 'main', + }, + { + select: { + id: true, + }, + } + ); + + // @ts-expect-error invalid model select key should be rejected + ormClient.user.findMany({ select: { invalidField: true } }); + + // @ts-expect-error invalid custom query select key should be rejected + ormClient.query.currentUser({ select: { invalidField: 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 = { + databasesByOwnerId: { + 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..9c4e6a305 --- /dev/null +++ b/graphql/test-app/src/type-tests/select-strictness-regressions.type-test.ts @@ -0,0 +1,200 @@ +/** + * Additional compile-time regression checks focused on strict selection behavior. + * + * These tests target edge cases around: + * - nested relation select options (filter/orderBy) + * - invalid relation option keys + * - default vs explicit selection result narrowing + * - custom ORM operation option contracts + */ + +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() { + const defaultDatabases = useDatabasesQuery({ selection: { first: 10 } }); + const defaultDatabaseId = defaultDatabases.data?.databases.nodes[0]?.id; + void defaultDatabaseId; + // @ts-expect-error default select for useDatabasesQuery should not expose name + defaultDatabases.data?.databases.nodes[0]?.name; + + 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; + + // @ts-expect-error relation select options should use filter, not where + useDatabasesQuery({ + selection: { + fields: { + schemas: { + where: { + schemaName: { equalTo: 'public' }, + }, + select: { + id: true, + }, + }, + }, + }, + }); + + // @ts-expect-error invalid field inside nested relation filter should be rejected + useDatabasesQuery({ + selection: { + fields: { + schemas: { + filter: { + invalidField: { equalTo: 'x' }, + }, + select: { + id: true, + }, + }, + }, + }, + }); + + // @ts-expect-error invalid orderBy literal should be rejected + useDatabasesQuery({ + selection: { + fields: { + schemas: { + orderBy: ['INVALID_ASC'], + select: { + id: true, + }, + }, + }, + }, + }); + + 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 defaultCurrentUser = ormClient.query.currentUser(); + type DefaultCurrentUser = Awaited>['currentUser']; + type _defaultCurrentUserOmitsUsername = Assert>; + + const selectedCurrentUser = ormClient.query.currentUser({ + select: { + id: true, + username: true, + }, + }); + type SelectedCurrentUser = Awaited>['currentUser']; + type _selectedCurrentUserHasUsername = Assert>; + + // @ts-expect-error custom ORM query options object requires select when provided + ormClient.query.currentUser({}); + + const defaultSignIn = ormClient.mutation.signIn({ + input: { + email: 'dev@example.com', + password: 'password', + rememberMe: true, + }, + }); + type DefaultSignIn = Awaited>['signIn']; + type _defaultSignInOmitsResult = Assert>; + + const selectedSignIn = ormClient.mutation.signIn( + { + input: { + email: 'dev@example.com', + password: 'password', + rememberMe: true, + }, + }, + { + select: { + clientMutationId: true, + result: { + select: { + accessToken: true, + userId: true, + }, + }, + }, + } + ); + type SelectedSignIn = Awaited>['signIn']; + type _selectedSignInHasResult = Assert>; + + ormClient.mutation.signIn( + { + input: { + email: 'dev@example.com', + password: 'password', + rememberMe: true, + }, + }, + // @ts-expect-error custom ORM mutation options object requires select when provided + {} + ); +} + +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/pnpm-lock.yaml b/pnpm-lock.yaml index e00bbd5de..b329b3a2c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,7 @@ settings: packageExtensionsChecksum: sha256-x8B4zkJ4KLRX+yspUWxuggXWlz6zrBLSIh72pNhpPiE= importers: + .: devDependencies: '@jest/test-sequencer': @@ -77,10 +78,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 @@ -1239,6 +1240,58 @@ importers: version: 0.1.10 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': @@ -2432,11 +2485,9 @@ importers: 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 +2495,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 +2724,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 +2733,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 +3391,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 +3399,38 @@ 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/cliui@8.0.2': - resolution: - { - integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==, - } - engines: { node: '>=12' } + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} '@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 +3438,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 +3479,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 +5402,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 +5477,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 +5486,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 +5506,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 +5514,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 +5729,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 +5887,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 +5909,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 +6016,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 +6074,607 @@ 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==} 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} 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==, - } + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported 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'} 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==, - } + 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-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} + 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 +6683,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 +6698,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 +6755,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 +6805,611 @@ 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' } + resolution: {integrity: sha512-YrdaZEAJwwjXGBTfZTNQ1LM7tmkdUaz2NpZEu7+zULcG4Wrlhd7cWSNZW0bxT3bP48k5N0mZWz8C2f9gc2+Geg==} + engines: {node: '>=18.0.0'} makage@0.1.10: - resolution: - { - integrity: sha512-IQKuRbHOrDgVNlydle+XRO5iMyaozBq4Bb9vhEzwxtvzyk08JkQo5qpfFRep0dSum53gECdX2gBoTmkWDHIfJA==, - } + resolution: {integrity: sha512-IQKuRbHOrDgVNlydle+XRO5iMyaozBq4Bb9vhEzwxtvzyk08JkQo5qpfFRep0dSum53gECdX2gBoTmkWDHIfJA==} 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@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 +7417,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 +7426,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 +7529,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 +7793,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 +7936,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 +8040,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' } + 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 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 +8627,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 +8641,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 +8960,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 +10024,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 +10126,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 @@ -14632,14 +10619,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 +10648,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 +11108,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 +11808,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 +12042,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 +12265,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 +12453,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 +13282,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 @@ -19314,6 +15434,8 @@ snapshots: dependencies: big-integer: 1.6.52 + nanoid@3.3.11: {} + napi-postinstall@0.3.4: {} natural-compare@1.4.0: {} @@ -19702,7 +15824,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 +16000,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 +16173,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 +16184,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 +16338,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 +16548,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 +16562,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 +16674,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 +17052,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: From 7497345baaa69a671837bf453bc8a72fa1fbf254 Mon Sep 17 00:00:00 2001 From: yyyyaaa Date: Sat, 7 Feb 2026 14:35:29 +0700 Subject: [PATCH 05/17] ci: ignore test-codegen-app changes --- .github/workflows/docker-launchql.yaml | 4 ++++ .github/workflows/notify-e2e.yml | 2 ++ .github/workflows/run-tests.yaml | 7 ++++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker-launchql.yaml b/.github/workflows/docker-launchql.yaml index 13856efc6..cf2d20d5c 100644 --- a/.github/workflows/docker-launchql.yaml +++ b/.github/workflows/docker-launchql.yaml @@ -6,11 +6,15 @@ on: - main - v1 - release/* + paths-ignore: + - 'graphql/test-app/**' pull_request: branches: - main - v1 types: [opened, reopened, synchronize, ready_for_review] + paths-ignore: + - 'graphql/test-app/**' workflow_dispatch: {} concurrency: diff --git a/.github/workflows/notify-e2e.yml b/.github/workflows/notify-e2e.yml index e12a58c6a..7afa067ea 100644 --- a/.github/workflows/notify-e2e.yml +++ b/.github/workflows/notify-e2e.yml @@ -6,6 +6,8 @@ name: Notify E2E Tests on: push: branches: [main] + paths-ignore: + - 'graphql/test-app/**' jobs: trigger-tests: diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 3142fb930..d1feffd65 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -4,10 +4,14 @@ on: branches: - main - v1 + paths-ignore: + - 'graphql/test-app/**' pull_request: branches: - main - v1 + paths-ignore: + - 'graphql/test-app/**' workflow_dispatch: workflow_call: @@ -190,7 +194,8 @@ jobs: run: pnpm install - name: build - run: pnpm run build + run: | + pnpm -r --filter '!@constructive-io/test-codegen-app' run build - name: seed app_user run: | From 283ddfa9910442429b08a46f5a0127e0da3a8c92 Mon Sep 17 00:00:00 2001 From: yyyyaaa Date: Sat, 7 Feb 2026 15:12:28 +0700 Subject: [PATCH 06/17] ci: ignore test package --- .github/workflows/docker-launchql.yaml | 2 ++ .github/workflows/notify-e2e.yml | 1 + .github/workflows/run-tests.yaml | 2 ++ package.json | 4 ++-- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-launchql.yaml b/.github/workflows/docker-launchql.yaml index cf2d20d5c..abf4d3196 100644 --- a/.github/workflows/docker-launchql.yaml +++ b/.github/workflows/docker-launchql.yaml @@ -8,6 +8,7 @@ on: - release/* paths-ignore: - 'graphql/test-app/**' + - 'graphql/test-codegen-app/**' pull_request: branches: - main @@ -15,6 +16,7 @@ on: types: [opened, reopened, synchronize, ready_for_review] paths-ignore: - 'graphql/test-app/**' + - 'graphql/test-codegen-app/**' workflow_dispatch: {} concurrency: diff --git a/.github/workflows/notify-e2e.yml b/.github/workflows/notify-e2e.yml index 7afa067ea..7f9e6f3d6 100644 --- a/.github/workflows/notify-e2e.yml +++ b/.github/workflows/notify-e2e.yml @@ -8,6 +8,7 @@ on: branches: [main] paths-ignore: - 'graphql/test-app/**' + - 'graphql/test-codegen-app/**' jobs: trigger-tests: diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index d1feffd65..015753008 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -6,12 +6,14 @@ on: - v1 paths-ignore: - 'graphql/test-app/**' + - 'graphql/test-codegen-app/**' pull_request: branches: - main - v1 paths-ignore: - 'graphql/test-app/**' + - 'graphql/test-codegen-app/**' workflow_dispatch: workflow_call: diff --git a/package.json b/package.json index 6ef5a5fb4..a784ca712 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ }, "scripts": { "clean": "pnpm -r run clean", - "build": "pnpm -r run build", - "build:dev": "pnpm -r run build:dev", + "build": "pnpm -r --filter '!@constructive-io/test-codegen-app' run build", + "build:dev": "pnpm -r --filter '!@constructive-io/test-codegen-app' run build:dev", "lint": "pnpm -r run lint", "internal:deps": "makage update-workspace", "deps": "pnpm up -r -i -L" From d2e748028fa4e1271cb35e1366a1018f1ad957b9 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sat, 7 Feb 2026 21:55:02 +0000 Subject: [PATCH 07/17] fix(codegen): convert string concatenation to Babel AST and template-copy patterns - Convert queries.ts, mutations.ts, custom-queries.ts, custom-mutations.ts from lines.push() string concatenation to Babel AST generation - Convert client.ts and selection.ts from string template literals to template-copy pattern - Add hooks-ast.ts shared helper library for Babel AST node construction - Add template files: hooks-client.ts, hooks-selection.ts - Add AGENTS.md with codegen rules (AST-only, no string concat, templates as files) - Update test snapshots for Babel formatting changes (whitespace/formatting only) --- graphql/codegen/AGENTS.md | 32 + .../react-query-hooks.test.ts.snap | 2580 +++++++++++------ graphql/codegen/src/core/codegen/client.ts | 73 +- .../src/core/codegen/custom-mutations.ts | 306 +- .../src/core/codegen/custom-queries.ts | 768 +++-- graphql/codegen/src/core/codegen/hooks-ast.ts | 874 ++++++ graphql/codegen/src/core/codegen/mutations.ts | 758 +++-- graphql/codegen/src/core/codegen/queries.ts | 1019 ++++--- graphql/codegen/src/core/codegen/selection.ts | 102 +- .../core/codegen/templates/hooks-client.ts | 49 + .../core/codegen/templates/hooks-selection.ts | 79 + 11 files changed, 4607 insertions(+), 2033 deletions(-) create mode 100644 graphql/codegen/AGENTS.md create mode 100644 graphql/codegen/src/core/codegen/hooks-ast.ts create mode 100644 graphql/codegen/src/core/codegen/templates/hooks-client.ts create mode 100644 graphql/codegen/src/core/codegen/templates/hooks-selection.ts 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/src/__tests__/codegen/__snapshots__/react-query-hooks.test.ts.snap b/graphql/codegen/src/__tests__/codegen/__snapshots__/react-query-hooks.test.ts.snap index 9ccd55d96..68b86cdec 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 @@ -187,37 +187,53 @@ exports[`Custom Mutation Hook Generators generateCustomMutationHook generates cu * DO NOT EDIT - changes will be overwritten */ -import { useMutation } from '@tanstack/react-query'; -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'; -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'; - -const defaultSelect = { token: true } as const; - -export function useLoginMutation( - params: { selection: ({ fields: S } & StrictSelect) } & Omit }, Error, LoginVariables>, 'mutationFn'> -): UseMutationResult<{ login: InferSelectResult }, Error, LoginVariables>; -export function useLoginMutation( - params?: { selection?: ({ fields?: undefined }) } & Omit }, Error, LoginVariables>, 'mutationFn'> -): UseMutationResult<{ login: InferSelectResult }, Error, LoginVariables>; -export function useLoginMutation( - params?: { selection?: SelectionConfig } & Omit, 'mutationFn'> -) { +import { useMutation } from "@tanstack/react-query"; +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"; +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"; +const defaultSelect = { + token: true +} as const; +export function useLoginMutation(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; +}, Error, LoginVariables>, "mutationFn">): UseMutationResult<{ + login: InferSelectResult; +}, Error, LoginVariables>; +export function useLoginMutation(params?: { + selection?: ({ + fields?: undefined; + }); +} & 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 ?? {}; + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; void _selection; return useMutation({ mutationKey: customMutationKeys.login(), - mutationFn: (variables: LoginVariables) => getClient().mutation.login(variables, { select: (args?.select ?? defaultSelect) as LoginPayloadSelect }).unwrap(), - ...mutationOptions, + mutationFn: (variables: LoginVariables) => getClient().mutation.login(variables, { + select: (args?.select ?? defaultSelect) as LoginPayloadSelect + }).unwrap(), + ...mutationOptions }); } " @@ -230,37 +246,53 @@ exports[`Custom Mutation Hook Generators generateCustomMutationHook generates cu * DO NOT EDIT - changes will be overwritten */ -import { useMutation } from '@tanstack/react-query'; -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'; -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'; - -const defaultSelect = { token: true } as const; - -export function useRegisterMutation( - params: { selection: ({ fields: S } & StrictSelect) } & Omit }, Error, RegisterVariables>, 'mutationFn'> -): UseMutationResult<{ register: InferSelectResult }, Error, RegisterVariables>; -export function useRegisterMutation( - params?: { selection?: ({ fields?: undefined }) } & Omit }, Error, RegisterVariables>, 'mutationFn'> -): UseMutationResult<{ register: InferSelectResult }, Error, RegisterVariables>; -export function useRegisterMutation( - params?: { selection?: SelectionConfig } & Omit, 'mutationFn'> -) { +import { useMutation } from "@tanstack/react-query"; +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"; +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"; +const defaultSelect = { + token: true +} as const; +export function useRegisterMutation(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; +}, Error, RegisterVariables>, "mutationFn">): UseMutationResult<{ + register: InferSelectResult; +}, Error, RegisterVariables>; +export function useRegisterMutation(params?: { + selection?: ({ + fields?: undefined; + }); +} & 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 ?? {}; + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; void _selection; return useMutation({ mutationKey: customMutationKeys.register(), - mutationFn: (variables: RegisterVariables) => getClient().mutation.register(variables, { select: (args?.select ?? defaultSelect) as RegisterPayloadSelect }).unwrap(), - ...mutationOptions, + mutationFn: (variables: RegisterVariables) => getClient().mutation.register(variables, { + select: (args?.select ?? defaultSelect) as RegisterPayloadSelect + }).unwrap(), + ...mutationOptions }); } " @@ -273,35 +305,51 @@ exports[`Custom Mutation Hook Generators generateCustomMutationHook generates cu * DO NOT EDIT - changes will be overwritten */ -import { useMutation } from '@tanstack/react-query'; -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'; -import type { LogoutPayloadSelect, LogoutPayload } from '../../orm/input-types'; -import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; - -export type { LogoutPayloadSelect } from '../../orm/input-types'; - -const defaultSelect = { success: true } as const; - -export function useLogoutMutation( - params: { selection: ({ fields: S } & StrictSelect) } & Omit }, Error, void>, 'mutationFn'> -): UseMutationResult<{ logout: InferSelectResult }, Error, void>; -export function useLogoutMutation( - params?: { selection?: ({ fields?: undefined }) } & Omit }, Error, void>, 'mutationFn'> -): UseMutationResult<{ logout: InferSelectResult }, Error, void>; -export function useLogoutMutation( - params?: { selection?: SelectionConfig } & Omit, 'mutationFn'> -) { +import { useMutation } from "@tanstack/react-query"; +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"; +import type { LogoutPayloadSelect, LogoutPayload } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { LogoutPayloadSelect } from "../../orm/input-types"; +const defaultSelect = { + success: true +} as const; +export function useLogoutMutation(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; +}, Error, void>, "mutationFn">): UseMutationResult<{ + logout: InferSelectResult; +}, Error, void>; +export function useLogoutMutation(params?: { + selection?: ({ + fields?: undefined; + }); +} & 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 ?? {}; + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; void _selection; return useMutation({ mutationKey: customMutationKeys.logout(), - mutationFn: () => getClient().mutation.logout({ select: (args?.select ?? defaultSelect) as LogoutPayloadSelect }).unwrap(), - ...mutationOptions, + mutationFn: () => getClient().mutation.logout({ + select: (args?.select ?? defaultSelect) as LogoutPayloadSelect + }).unwrap(), + ...mutationOptions }); } " @@ -314,35 +362,51 @@ exports[`Custom Mutation Hook Generators generateCustomMutationHook generates cu * DO NOT EDIT - changes will be overwritten */ -import { useMutation } from '@tanstack/react-query'; -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'; - -const defaultSelect = { token: true } as const; - -export function useLoginMutation( - params: { selection: ({ fields: S } & StrictSelect) } & Omit }, Error, LoginVariables>, 'mutationFn'> -): UseMutationResult<{ login: InferSelectResult }, Error, LoginVariables>; -export function useLoginMutation( - params?: { selection?: ({ fields?: undefined }) } & Omit }, Error, LoginVariables>, 'mutationFn'> -): UseMutationResult<{ login: InferSelectResult }, Error, LoginVariables>; -export function useLoginMutation( - params?: { selection?: SelectionConfig } & Omit, 'mutationFn'> -) { +import { useMutation } from "@tanstack/react-query"; +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"; +const defaultSelect = { + token: true +} as const; +export function useLoginMutation(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; +}, Error, LoginVariables>, "mutationFn">): UseMutationResult<{ + login: InferSelectResult; +}, Error, LoginVariables>; +export function useLoginMutation(params?: { + selection?: ({ + fields?: undefined; + }); +} & 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 ?? {}; + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; void _selection; return useMutation({ - mutationFn: (variables: LoginVariables) => getClient().mutation.login(variables, { select: (args?.select ?? defaultSelect) as LoginPayloadSelect }).unwrap(), - ...mutationOptions, + mutationFn: (variables: LoginVariables) => getClient().mutation.login(variables, { + select: (args?.select ?? defaultSelect) as LoginPayloadSelect + }).unwrap(), + ...mutationOptions }); } " @@ -355,105 +419,141 @@ exports[`Custom Query Hook Generators generateCustomQueryHook generates custom q * DO NOT EDIT - changes will be overwritten */ -import { useQuery } from '@tanstack/react-query'; -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'; -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'; - -const defaultSelect = { id: true } as const; - +import { useQuery } from "@tanstack/react-query"; +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"; +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"; +const defaultSelect = { + id: true +} as const; /** Query key factory - re-exported from query-keys.ts */ export const searchUsersQueryKey = customQueryKeys.searchUsers; - /** * Search users by name or email - * + * * @example * \`\`\`tsx * const { data, isLoading } = useSearchUsersQuery({ query, limit }); - * + * * if (data?.searchUsers) { * console.log(data.searchUsers); * } * \`\`\` */ -export function useSearchUsersQuery[] }>( - params: { variables: SearchUsersVariables; selection: ({ fields: S } & StrictSelect) } & Omit[] }, Error, TData>, 'queryKey' | 'queryFn'> -): UseQueryResult; -export function useSearchUsersQuery[] }>( - params: { variables: SearchUsersVariables; selection?: ({ fields?: undefined }) } & Omit[] }, Error, TData>, 'queryKey' | 'queryFn'> -): UseQueryResult; -export function useSearchUsersQuery( - params: { variables: SearchUsersVariables; selection?: SelectionConfig } & 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?: ({ + fields?: undefined; + }); +} & 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 ?? {}; + const { + variables: _variables, + selection: _selection, + ...queryOptions + } = params ?? {}; void _variables; void _selection; return useQuery({ queryKey: searchUsersQueryKey(variables), - queryFn: () => getClient().query.searchUsers(variables!, { select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + queryFn: () => getClient().query.searchUsers(variables!, { + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(), enabled: !!variables && params?.enabled !== false, - ...queryOptions, + ...queryOptions }); } - /** * Fetch searchUsers without React hooks - * + * * @example * \`\`\`ts * const data = await fetchSearchUsersQuery({ query, limit }); * \`\`\` */ -export async function fetchSearchUsersQuery( - params: { variables: SearchUsersVariables; selection: ({ fields: S } & StrictSelect) } -): Promise<{ searchUsers: InferSelectResult[] }>; -export async function fetchSearchUsersQuery( - params: { variables: SearchUsersVariables; selection?: ({ fields?: undefined }) } -): Promise<{ searchUsers: InferSelectResult[] }>; -export async function fetchSearchUsersQuery( - params: { variables: SearchUsersVariables; selection?: SelectionConfig }, -) { +export async function fetchSearchUsersQuery(params: { + variables: SearchUsersVariables; + selection: ({ + fields: S; + } & StrictSelect); +}): Promise<{ + searchUsers: InferSelectResult[]; +}>; +export async function fetchSearchUsersQuery(params: { + variables: SearchUsersVariables; + selection?: ({ + fields?: undefined; + }); +}): 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 ?? defaultSelect) as UserSelect }).unwrap(); + return getClient().query.searchUsers(variables!, { + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(); } - /** * Prefetch searchUsers for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchSearchUsersQuery(queryClient, { query, limit }); * \`\`\` */ -export async function prefetchSearchUsersQuery( - queryClient: QueryClient, - params: { variables: SearchUsersVariables; selection: ({ fields: S } & StrictSelect) } -): Promise; -export async function prefetchSearchUsersQuery( - queryClient: QueryClient, - params: { variables: SearchUsersVariables; selection?: ({ fields?: undefined }) } -): Promise; -export async function prefetchSearchUsersQuery( - queryClient: QueryClient, - params: { variables: SearchUsersVariables; selection?: SelectionConfig } -): 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?: ({ + fields?: undefined; + }); +}): Promise; +export async function prefetchSearchUsersQuery(queryClient: QueryClient, params: { + variables: SearchUsersVariables; + selection?: SelectionConfig; +}): void { const variables = params?.variables; const args = buildSelectionArgs(params?.selection); await queryClient.prefetchQuery({ queryKey: searchUsersQueryKey(variables), - queryFn: () => getClient().query.searchUsers(variables!, { select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + queryFn: () => getClient().query.searchUsers(variables!, { + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap() }); } " @@ -466,98 +566,124 @@ exports[`Custom Query Hook Generators generateCustomQueryHook generates custom q * DO NOT EDIT - changes will be overwritten */ -import { useQuery } from '@tanstack/react-query'; -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'; -import type { UserSelect, User } from '../../orm/input-types'; -import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; - -export type { UserSelect } from '../../orm/input-types'; - -const defaultSelect = { id: true } as const; - +import { useQuery } from "@tanstack/react-query"; +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"; +import type { UserSelect, User } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { UserSelect } from "../../orm/input-types"; +const defaultSelect = { + id: true +} as const; /** Query key factory - re-exported from query-keys.ts */ export const currentUserQueryKey = customQueryKeys.currentUser; - /** * Get the current authenticated user - * + * * @example * \`\`\`tsx * const { data, isLoading } = useCurrentUserQuery(); - * + * * if (data?.currentUser) { * console.log(data.currentUser); * } * \`\`\` */ -export function useCurrentUserQuery }>( - params: { selection: ({ fields: S } & StrictSelect) } & Omit }, Error, TData>, 'queryKey' | 'queryFn'> -): UseQueryResult; -export function useCurrentUserQuery }>( - params?: { selection?: ({ fields?: undefined }) } & Omit }, Error, TData>, 'queryKey' | 'queryFn'> -): UseQueryResult; -export function useCurrentUserQuery( - params?: { selection?: SelectionConfig } & Omit, 'queryKey' | 'queryFn'> -) { +export function useCurrentUserQuery; +}>(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; +}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; +export function useCurrentUserQuery; +}>(params?: { + selection?: ({ + fields?: undefined; + }); +} & 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 ?? {}; + const { + selection: _selection, + ...queryOptions + } = params ?? {}; void _selection; return useQuery({ queryKey: currentUserQueryKey(), - queryFn: () => getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), - ...queryOptions, + queryFn: () => getClient().query.currentUser({ + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(), + ...queryOptions }); } - /** * Fetch currentUser without React hooks - * + * * @example * \`\`\`ts * const data = await fetchCurrentUserQuery(); * \`\`\` */ -export async function fetchCurrentUserQuery( - params: { selection: ({ fields: S } & StrictSelect) } -): Promise<{ currentUser: InferSelectResult }>; -export async function fetchCurrentUserQuery( - params?: { selection?: ({ fields?: undefined }) }, -): Promise<{ currentUser: InferSelectResult }>; -export async function fetchCurrentUserQuery( - params?: { selection?: SelectionConfig }, -) { +export async function fetchCurrentUserQuery(params: { + selection: ({ + fields: S; + } & StrictSelect); +}): Promise<{ + currentUser: InferSelectResult; +}>; +export async function fetchCurrentUserQuery(params?: { + selection?: ({ + fields?: undefined; + }); +}): Promise<{ + currentUser: InferSelectResult; +}>; +export async function fetchCurrentUserQuery(params?: { + selection?: SelectionConfig; +}) { const args = buildSelectionArgs(params?.selection); - return getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(); + return getClient().query.currentUser({ + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(); } - /** * Prefetch currentUser for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchCurrentUserQuery(queryClient); * \`\`\` */ -export async function prefetchCurrentUserQuery( - queryClient: QueryClient, - params: { selection: ({ fields: S } & StrictSelect) } -): Promise; -export async function prefetchCurrentUserQuery( - queryClient: QueryClient, - params?: { selection?: ({ fields?: undefined }) } -): Promise; -export async function prefetchCurrentUserQuery( - queryClient: QueryClient, - params?: { selection?: SelectionConfig } -): Promise { +export async function prefetchCurrentUserQuery(queryClient: QueryClient, params: { + selection: ({ + fields: S; + } & StrictSelect); +}): Promise; +export async function prefetchCurrentUserQuery(queryClient: QueryClient, params?: { + selection?: ({ + fields?: undefined; + }); +}): Promise; +export async function prefetchCurrentUserQuery(queryClient: QueryClient, params?: { + selection?: SelectionConfig; +}): void { const args = buildSelectionArgs(params?.selection); await queryClient.prefetchQuery({ queryKey: currentUserQueryKey(), - queryFn: () => getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + queryFn: () => getClient().query.currentUser({ + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap() }); } " @@ -570,97 +696,123 @@ exports[`Custom Query Hook Generators generateCustomQueryHook generates custom q * DO NOT EDIT - changes will be overwritten */ -import { useQuery } from '@tanstack/react-query'; -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'; - -const defaultSelect = { id: true } as const; - +import { useQuery } from "@tanstack/react-query"; +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"; +const defaultSelect = { + id: true +} as const; /** Query key factory for caching */ -export const currentUserQueryKey = () => ['currentUser'] as const; - +export const currentUserQueryKey = () => ["currentUser"] as const; /** * Get the current authenticated user - * + * * @example * \`\`\`tsx * const { data, isLoading } = useCurrentUserQuery(); - * + * * if (data?.currentUser) { * console.log(data.currentUser); * } * \`\`\` */ -export function useCurrentUserQuery }>( - params: { selection: ({ fields: S } & StrictSelect) } & Omit }, Error, TData>, 'queryKey' | 'queryFn'> -): UseQueryResult; -export function useCurrentUserQuery }>( - params?: { selection?: ({ fields?: undefined }) } & Omit }, Error, TData>, 'queryKey' | 'queryFn'> -): UseQueryResult; -export function useCurrentUserQuery( - params?: { selection?: SelectionConfig } & Omit, 'queryKey' | 'queryFn'> -) { +export function useCurrentUserQuery; +}>(params: { + selection: ({ + fields: S; + } & StrictSelect); +} & Omit; +}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; +export function useCurrentUserQuery; +}>(params?: { + selection?: ({ + fields?: undefined; + }); +} & 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 ?? {}; + const { + selection: _selection, + ...queryOptions + } = params ?? {}; void _selection; return useQuery({ queryKey: currentUserQueryKey(), - queryFn: () => getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), - ...queryOptions, + queryFn: () => getClient().query.currentUser({ + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(), + ...queryOptions }); } - /** * Fetch currentUser without React hooks - * + * * @example * \`\`\`ts * const data = await fetchCurrentUserQuery(); * \`\`\` */ -export async function fetchCurrentUserQuery( - params: { selection: ({ fields: S } & StrictSelect) } -): Promise<{ currentUser: InferSelectResult }>; -export async function fetchCurrentUserQuery( - params?: { selection?: ({ fields?: undefined }) }, -): Promise<{ currentUser: InferSelectResult }>; -export async function fetchCurrentUserQuery( - params?: { selection?: SelectionConfig }, -) { +export async function fetchCurrentUserQuery(params: { + selection: ({ + fields: S; + } & StrictSelect); +}): Promise<{ + currentUser: InferSelectResult; +}>; +export async function fetchCurrentUserQuery(params?: { + selection?: ({ + fields?: undefined; + }); +}): Promise<{ + currentUser: InferSelectResult; +}>; +export async function fetchCurrentUserQuery(params?: { + selection?: SelectionConfig; +}) { const args = buildSelectionArgs(params?.selection); - return getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(); + return getClient().query.currentUser({ + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(); } - /** * Prefetch currentUser for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchCurrentUserQuery(queryClient); * \`\`\` */ -export async function prefetchCurrentUserQuery( - queryClient: QueryClient, - params: { selection: ({ fields: S } & StrictSelect) } -): Promise; -export async function prefetchCurrentUserQuery( - queryClient: QueryClient, - params?: { selection?: ({ fields?: undefined }) } -): Promise; -export async function prefetchCurrentUserQuery( - queryClient: QueryClient, - params?: { selection?: SelectionConfig } -): Promise { +export async function prefetchCurrentUserQuery(queryClient: QueryClient, params: { + selection: ({ + fields: S; + } & StrictSelect); +}): Promise; +export async function prefetchCurrentUserQuery(queryClient: QueryClient, params?: { + selection?: ({ + fields?: undefined; + }); +}): Promise; +export async function prefetchCurrentUserQuery(queryClient: QueryClient, params?: { + selection?: SelectionConfig; +}): void { const args = buildSelectionArgs(params?.selection); await queryClient.prefetchQuery({ queryKey: currentUserQueryKey(), - queryFn: () => getClient().query.currentUser({ select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + queryFn: () => getClient().query.currentUser({ + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap() }); } " @@ -673,56 +825,79 @@ exports[`Mutation Hook Generators generateCreateMutationHook generates create mu * DO NOT EDIT - changes will be overwritten */ -import { useMutation, useQueryClient } from '@tanstack/react-query'; -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'; -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'; - -const defaultSelect = { id: true } as const; - +import { useMutation, useQueryClient } from "@tanstack/react-query"; +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"; +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"; +const defaultSelect = { + id: true +} as const; /** * Mutation hook for creating a User - * + * * @example * \`\`\`tsx * const { mutate, isPending } = useCreateUserMutation({ * selection: { fields: { id: true, name: true } }, * }); - * + * * mutate({ name: 'New item' }); * \`\`\` */ -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?: ({ fields?: undefined }) } & Omit } }, Error, CreateUserInput['user']>, 'mutationFn'> -): UseMutationResult<{ createUser: { user: InferSelectResult } }, Error, CreateUserInput['user']>; -export function useCreateUserMutation( - params?: { selection?: SelectionConfig } & 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?: ({ + fields?: undefined; + }); +} & 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 ?? {}; + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; void _selection; const queryClient = useQueryClient(); return useMutation({ mutationKey: userMutationKeys.create(), - mutationFn: (data: CreateUserInput['user']) => getClient().user.create({ data, select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + mutationFn: (data: CreateUserInput["user"]) => getClient().user.create({ + data, + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(), onSuccess: () => { - queryClient.invalidateQueries({ queryKey: userKeys.lists() }); + queryClient.invalidateQueries({ + queryKey: userKeys.lists() + }); }, - ...mutationOptions, + ...mutationOptions }); } " @@ -735,56 +910,79 @@ exports[`Mutation Hook Generators generateCreateMutationHook generates create mu * DO NOT EDIT - changes will be overwritten */ -import { useMutation, useQueryClient } from '@tanstack/react-query'; -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 { postMutationKeys } from '../mutation-keys'; -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'; - -const defaultSelect = { id: true } as const; - +import { useMutation, useQueryClient } from "@tanstack/react-query"; +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 { postMutationKeys } from "../mutation-keys"; +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"; +const defaultSelect = { + id: true +} as const; /** * Mutation hook for creating a Post - * + * * @example * \`\`\`tsx * const { mutate, isPending } = useCreatePostMutation({ * selection: { fields: { id: true, name: true } }, * }); - * + * * mutate({ name: 'New item' }); * \`\`\` */ -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?: ({ fields?: undefined }) } & Omit } }, Error, CreatePostInput['post']>, 'mutationFn'> -): UseMutationResult<{ createPost: { post: InferSelectResult } }, Error, CreatePostInput['post']>; -export function useCreatePostMutation( - params?: { selection?: SelectionConfig } & 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?: ({ + fields?: undefined; + }); +} & 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 ?? {}; + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; void _selection; const queryClient = useQueryClient(); return useMutation({ mutationKey: postMutationKeys.create(), - mutationFn: (data: CreatePostInput['post']) => getClient().post.create({ data, select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(), + mutationFn: (data: CreatePostInput["post"]) => getClient().post.create({ + data, + select: (args?.select ?? defaultSelect) as PostSelect + }).unwrap(), onSuccess: () => { - queryClient.invalidateQueries({ queryKey: postKeys.lists() }); + queryClient.invalidateQueries({ + queryKey: postKeys.lists() + }); }, - ...mutationOptions, + ...mutationOptions }); } " @@ -797,53 +995,76 @@ exports[`Mutation Hook Generators generateCreateMutationHook generates create mu * DO NOT EDIT - changes will be overwritten */ -import { useMutation, useQueryClient } from '@tanstack/react-query'; -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'; - -const defaultSelect = { id: true } as const; - +import { useMutation, useQueryClient } from "@tanstack/react-query"; +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"; +const defaultSelect = { + id: true +} as const; /** * Mutation hook for creating a User - * + * * @example * \`\`\`tsx * const { mutate, isPending } = useCreateUserMutation({ * selection: { fields: { id: true, name: true } }, * }); - * + * * mutate({ name: 'New item' }); * \`\`\` */ -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?: ({ fields?: undefined }) } & Omit } }, Error, CreateUserInput['user']>, 'mutationFn'> -): UseMutationResult<{ createUser: { user: InferSelectResult } }, Error, CreateUserInput['user']>; -export function useCreateUserMutation( - params?: { selection?: SelectionConfig } & 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?: ({ + fields?: undefined; + }); +} & 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 ?? {}; + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; void _selection; const queryClient = useQueryClient(); return useMutation({ - mutationFn: (data: CreateUserInput['user']) => getClient().user.create({ data, select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + mutationFn: (data: CreateUserInput["user"]) => getClient().user.create({ + data, + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(), onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['user', 'list'] }); + queryClient.invalidateQueries({ + queryKey: ["user", "list"] + }); }, - ...mutationOptions, + ...mutationOptions }); } " @@ -856,56 +1077,98 @@ exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mu * DO NOT EDIT - changes will be overwritten */ -import { useMutation, useQueryClient } from '@tanstack/react-query'; -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'; -import type { - UserSelect, - UserWithRelations, -} from '../../orm/input-types'; -import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; - -export type { UserSelect, UserWithRelations } from '../../orm/input-types'; - -const defaultSelect = { id: true } as const; - +import { useMutation, useQueryClient } from "@tanstack/react-query"; +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"; +import type { UserSelect, UserWithRelations } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { UserSelect, UserWithRelations } from "../../orm/input-types"; +const defaultSelect = { + id: true +} as const; /** * Mutation hook for deleting a User - * + * * @example * \`\`\`tsx * const { mutate, isPending } = useDeleteUserMutation({ * selection: { fields: { id: true } }, * }); - * + * * mutate({ id: 'value-to-delete' }); * \`\`\` */ -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?: ({ fields?: undefined }) } & Omit } }, Error, { id: string }>, 'mutationFn'> -): UseMutationResult<{ deleteUser: { user: InferSelectResult } }, Error, { id: string }>; -export function useDeleteUserMutation( - params?: { selection?: SelectionConfig } & 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?: ({ + fields?: undefined; + }); +} & 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 ?? {}; + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; void _selection; const queryClient = useQueryClient(); return useMutation({ mutationKey: userMutationKeys.all, - mutationFn: ({ id }: { id: string }) => getClient().user.delete({ where: { id }, select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + mutationFn: ({ + id + }: { + id: string; + }) => getClient().user.delete({ + where: { + id + }, + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(), onSuccess: (_, variables) => { - queryClient.removeQueries({ queryKey: userKeys.detail(variables.id) }); - queryClient.invalidateQueries({ queryKey: userKeys.lists() }); + queryClient.removeQueries({ + queryKey: userKeys.detail(variables.id) + }); + queryClient.invalidateQueries({ + queryKey: userKeys.lists() + }); }, - ...mutationOptions, + ...mutationOptions }); } " @@ -918,56 +1181,98 @@ exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mu * DO NOT EDIT - changes will be overwritten */ -import { useMutation, useQueryClient } from '@tanstack/react-query'; -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 { postMutationKeys } from '../mutation-keys'; -import type { - PostSelect, - PostWithRelations, -} from '../../orm/input-types'; -import type { InferSelectResult, StrictSelect } from '../../orm/select-types'; - -export type { PostSelect, PostWithRelations } from '../../orm/input-types'; - -const defaultSelect = { id: true } as const; - +import { useMutation, useQueryClient } from "@tanstack/react-query"; +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 { postMutationKeys } from "../mutation-keys"; +import type { PostSelect, PostWithRelations } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { PostSelect, PostWithRelations } from "../../orm/input-types"; +const defaultSelect = { + id: true +} as const; /** * Mutation hook for deleting a Post - * + * * @example * \`\`\`tsx * const { mutate, isPending } = useDeletePostMutation({ * selection: { fields: { id: true } }, * }); - * + * * mutate({ id: 'value-to-delete' }); * \`\`\` */ -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?: ({ fields?: undefined }) } & Omit } }, Error, { id: string }>, 'mutationFn'> -): UseMutationResult<{ deletePost: { post: InferSelectResult } }, Error, { id: string }>; -export function useDeletePostMutation( - params?: { selection?: SelectionConfig } & 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?: ({ + fields?: undefined; + }); +} & 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 ?? {}; + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; void _selection; const queryClient = useQueryClient(); return useMutation({ mutationKey: postMutationKeys.all, - mutationFn: ({ id }: { id: string }) => getClient().post.delete({ where: { id }, select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(), + mutationFn: ({ + id + }: { + id: string; + }) => getClient().post.delete({ + where: { + id + }, + select: (args?.select ?? defaultSelect) as PostSelect + }).unwrap(), onSuccess: (_, variables) => { - queryClient.removeQueries({ queryKey: postKeys.detail(variables.id) }); - queryClient.invalidateQueries({ queryKey: postKeys.lists() }); + queryClient.removeQueries({ + queryKey: postKeys.detail(variables.id) + }); + queryClient.invalidateQueries({ + queryKey: postKeys.lists() + }); }, - ...mutationOptions, + ...mutationOptions }); } " @@ -980,53 +1285,95 @@ exports[`Mutation Hook Generators generateDeleteMutationHook generates delete mu * DO NOT EDIT - changes will be overwritten */ -import { useMutation, useQueryClient } from '@tanstack/react-query'; -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'; - -const defaultSelect = { id: true } as const; - +import { useMutation, useQueryClient } from "@tanstack/react-query"; +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"; +const defaultSelect = { + id: true +} as const; /** * Mutation hook for deleting a User - * + * * @example * \`\`\`tsx * const { mutate, isPending } = useDeleteUserMutation({ * selection: { fields: { id: true } }, * }); - * + * * mutate({ id: 'value-to-delete' }); * \`\`\` */ -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?: ({ fields?: undefined }) } & Omit } }, Error, { id: string }>, 'mutationFn'> -): UseMutationResult<{ deleteUser: { user: InferSelectResult } }, Error, { id: string }>; -export function useDeleteUserMutation( - params?: { selection?: SelectionConfig } & 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?: ({ + fields?: undefined; + }); +} & 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 ?? {}; + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; void _selection; const queryClient = useQueryClient(); return useMutation({ - mutationFn: ({ id }: { id: string }) => getClient().user.delete({ where: { id }, select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + mutationFn: ({ + id + }: { + id: string; + }) => getClient().user.delete({ + where: { + id + }, + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(), onSuccess: (_, variables) => { - queryClient.removeQueries({ queryKey: ['user', 'detail', variables.id] }); - queryClient.invalidateQueries({ queryKey: ['user', 'list'] }); + queryClient.removeQueries({ + queryKey: ["user", "detail", variables.id] + }); + queryClient.invalidateQueries({ + queryKey: ["user", "list"] + }); }, - ...mutationOptions, + ...mutationOptions }); } " @@ -1039,57 +1386,106 @@ exports[`Mutation Hook Generators generateUpdateMutationHook generates update mu * DO NOT EDIT - changes will be overwritten */ -import { useMutation, useQueryClient } from '@tanstack/react-query'; -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'; -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'; - -const defaultSelect = { id: true } as const; - +import { useMutation, useQueryClient } from "@tanstack/react-query"; +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"; +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"; +const defaultSelect = { + id: true +} as const; /** * Mutation hook for updating a User - * + * * @example * \`\`\`tsx * const { mutate, isPending } = useUpdateUserMutation({ * selection: { fields: { id: true, name: true } }, * }); - * + * * mutate({ id: 'value-here', patch: { name: 'Updated' } }); * \`\`\` */ -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?: ({ fields?: undefined }) } & Omit } }, Error, { id: string; patch: UserPatch }>, 'mutationFn'> -): UseMutationResult<{ updateUser: { user: InferSelectResult } }, Error, { id: string; patch: UserPatch }>; -export function useUpdateUserMutation( - params?: { selection?: SelectionConfig } & 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?: ({ + fields?: undefined; + }); +} & 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 ?? {}; + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; void _selection; const queryClient = useQueryClient(); return useMutation({ mutationKey: userMutationKeys.all, - mutationFn: ({ id, patch }: { id: string; patch: UserPatch }) => getClient().user.update({ where: { id }, data: patch, select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + mutationFn: ({ + id, + patch + }: { + id: string; + patch: UserPatch; + }) => getClient().user.update({ + where: { + id + }, + data: patch, + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(), onSuccess: (_, variables) => { - queryClient.invalidateQueries({ queryKey: userKeys.detail(variables.id) }); - queryClient.invalidateQueries({ queryKey: userKeys.lists() }); + queryClient.invalidateQueries({ + queryKey: userKeys.detail(variables.id) + }); + queryClient.invalidateQueries({ + queryKey: userKeys.lists() + }); }, - ...mutationOptions, + ...mutationOptions }); } " @@ -1102,57 +1498,106 @@ exports[`Mutation Hook Generators generateUpdateMutationHook generates update mu * DO NOT EDIT - changes will be overwritten */ -import { useMutation, useQueryClient } from '@tanstack/react-query'; -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 { postMutationKeys } from '../mutation-keys'; -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'; - -const defaultSelect = { id: true } as const; - +import { useMutation, useQueryClient } from "@tanstack/react-query"; +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 { postMutationKeys } from "../mutation-keys"; +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"; +const defaultSelect = { + id: true +} as const; /** * Mutation hook for updating a Post - * + * * @example * \`\`\`tsx * const { mutate, isPending } = useUpdatePostMutation({ * selection: { fields: { id: true, name: true } }, * }); - * + * * mutate({ id: 'value-here', patch: { name: 'Updated' } }); * \`\`\` */ -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?: ({ fields?: undefined }) } & Omit } }, Error, { id: string; patch: PostPatch }>, 'mutationFn'> -): UseMutationResult<{ updatePost: { post: InferSelectResult } }, Error, { id: string; patch: PostPatch }>; -export function useUpdatePostMutation( - params?: { selection?: SelectionConfig } & 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?: ({ + fields?: undefined; + }); +} & 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 ?? {}; + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; void _selection; const queryClient = useQueryClient(); return useMutation({ mutationKey: postMutationKeys.all, - mutationFn: ({ id, patch }: { id: string; patch: PostPatch }) => getClient().post.update({ where: { id }, data: patch, select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(), + mutationFn: ({ + id, + patch + }: { + id: string; + patch: PostPatch; + }) => getClient().post.update({ + where: { + id + }, + data: patch, + select: (args?.select ?? defaultSelect) as PostSelect + }).unwrap(), onSuccess: (_, variables) => { - queryClient.invalidateQueries({ queryKey: postKeys.detail(variables.id) }); - queryClient.invalidateQueries({ queryKey: postKeys.lists() }); + queryClient.invalidateQueries({ + queryKey: postKeys.detail(variables.id) + }); + queryClient.invalidateQueries({ + queryKey: postKeys.lists() + }); }, - ...mutationOptions, + ...mutationOptions }); } " @@ -1165,54 +1610,103 @@ exports[`Mutation Hook Generators generateUpdateMutationHook generates update mu * DO NOT EDIT - changes will be overwritten */ -import { useMutation, useQueryClient } from '@tanstack/react-query'; -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'; - -const defaultSelect = { id: true } as const; - +import { useMutation, useQueryClient } from "@tanstack/react-query"; +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"; +const defaultSelect = { + id: true +} as const; /** * Mutation hook for updating a User - * + * * @example * \`\`\`tsx * const { mutate, isPending } = useUpdateUserMutation({ * selection: { fields: { id: true, name: true } }, * }); - * + * * mutate({ id: 'value-here', patch: { name: 'Updated' } }); * \`\`\` */ -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?: ({ fields?: undefined }) } & Omit } }, Error, { id: string; patch: UserPatch }>, 'mutationFn'> -): UseMutationResult<{ updateUser: { user: InferSelectResult } }, Error, { id: string; patch: UserPatch }>; -export function useUpdateUserMutation( - params?: { selection?: SelectionConfig } & 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?: ({ + fields?: undefined; + }); +} & 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 ?? {}; + const { + selection: _selection, + ...mutationOptions + } = params ?? {}; void _selection; const queryClient = useQueryClient(); return useMutation({ - mutationFn: ({ id, patch }: { id: string; patch: UserPatch }) => getClient().user.update({ where: { id }, data: patch, select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + mutationFn: ({ + id, + patch + }: { + id: string; + patch: UserPatch; + }) => getClient().user.update({ + where: { + id + }, + data: patch, + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(), onSuccess: (_, variables) => { - queryClient.invalidateQueries({ queryKey: ['user', 'detail', variables.id] }); - queryClient.invalidateQueries({ queryKey: ['user', 'list'] }); + queryClient.invalidateQueries({ + queryKey: ["user", "detail", variables.id] + }); + queryClient.invalidateQueries({ + queryKey: ["user", "list"] + }); }, - ...mutationOptions, + ...mutationOptions }); } " @@ -1225,35 +1719,23 @@ exports[`Query Hook Generators generateListQueryHook generates list query hook f * DO NOT EDIT - changes will be overwritten */ -import { useQuery } from '@tanstack/react-query'; -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'; -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'; - -const defaultSelect = { id: true } as const; - +import { useQuery } from "@tanstack/react-query"; +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"; +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"; +const defaultSelect = { + id: true +} as const; /** Query key factory - re-exported from query-keys.ts */ export const usersQueryKey = userKeys.list; - /** * Query hook for fetching User list - * + * * @example * \`\`\`tsx * const { data, isLoading } = useUsersQuery({ @@ -1266,29 +1748,46 @@ export const usersQueryKey = userKeys.list; * }); * \`\`\` */ -export function useUsersQuery> }>( - params: { selection: ({ fields: S } & Omit, 'fields'> & StrictSelect) } & Omit> }, Error, TData>, 'queryKey' | 'queryFn'> -): UseQueryResult; -export function useUsersQuery> }>( - params?: { selection?: (Omit, 'fields'> & { fields?: undefined }) } & Omit> }, Error, TData>, 'queryKey' | 'queryFn'> -): UseQueryResult; -export function useUsersQuery( - params?: { selection?: ListSelectionConfig } & Omit, 'queryKey' | 'queryFn'> -) { +export function useUsersQuery>; +}>(params: { + selection: { + fields: S; + } & Omit, "fields"> & StrictSelect; +} & Omit>; +}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; +export function useUsersQuery>; +}>(params?: { + selection?: Omit, "fields"> & { + fields?: undefined; + }; +} & Omit>; +}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; +export function useUsersQuery(params?: { + selection?: ListSelectionConfig; +} & Omit, "queryKey" | "queryFn">) { const selection = params?.selection; const args = buildListSelectionArgs(selection); - const { selection: _selection, ...queryOptions } = params ?? {}; + const { + selection: _selection, + ...queryOptions + } = params ?? {}; void _selection; return useQuery({ queryKey: userKeys.list(args), - queryFn: () => getClient().user.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), - ...queryOptions, + queryFn: () => getClient().user.findMany({ + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(), + ...queryOptions }); } - /** * Fetch User list without React hooks - * + * * @example * \`\`\`ts * const data = await fetchUsersQuery({ @@ -1299,43 +1798,57 @@ export function useUsersQuery( * }); * \`\`\` */ -export async function fetchUsersQuery( - params: { selection: ({ fields: S } & Omit, 'fields'> & StrictSelect) } -): Promise<{ users: ConnectionResult> }>; -export async function fetchUsersQuery( - params?: { selection?: (Omit, 'fields'> & { fields?: undefined }) } -): Promise<{ users: ConnectionResult> }>; -export async function fetchUsersQuery( - params?: { selection?: ListSelectionConfig } -) { - const args = buildListSelectionArgs(params?.selection); - return getClient().user.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(); +export async function fetchUsersQuery(params: { + selection: { + fields: S; + } & Omit, "fields"> & StrictSelect; +}): Promise<{ + users: ConnectionResult>; +}>; +export async function fetchUsersQuery(params?: { + selection?: Omit, "fields"> & { + fields?: undefined; + }; +}): Promise<{ + users: ConnectionResult>; +}>; +export async function fetchUsersQuery(params?: { + selection?: ListSelectionConfig; +}) { + const args = buildListSelectionArgs(selection); + return getClient().user.findMany({ + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(); } - /** * Prefetch User list for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchUsersQuery(queryClient, { selection: { first: 10 } }); * \`\`\` */ -export async function prefetchUsersQuery( - queryClient: QueryClient, - params: { selection: ({ fields: S } & Omit, 'fields'> & StrictSelect) } -): Promise; -export async function prefetchUsersQuery( - queryClient: QueryClient, - params?: { selection?: (Omit, 'fields'> & { fields?: undefined }) } -): Promise; -export async function prefetchUsersQuery( - queryClient: QueryClient, - params?: { selection?: ListSelectionConfig } -): Promise { - const args = buildListSelectionArgs(params?.selection); +export async function prefetchUsersQuery(queryClient: QueryClient, params: { + selection: { + fields: S; + } & Omit, "fields"> & StrictSelect; +}): Promise; +export async function prefetchUsersQuery(queryClient: QueryClient, params?: { + selection?: Omit, "fields"> & { + fields?: undefined; + }; +}): Promise; +export async function prefetchUsersQuery(queryClient: QueryClient, params?: { + selection?: ListSelectionConfig; +}): void { + const args = buildListSelectionArgs(selection); await queryClient.prefetchQuery({ queryKey: userKeys.list(args), - queryFn: () => getClient().user.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + queryFn: () => getClient().user.findMany({ + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap() }); } " @@ -1348,36 +1861,24 @@ exports[`Query Hook Generators generateListQueryHook generates list query hook f * DO NOT EDIT - changes will be overwritten */ -import { useQuery } from '@tanstack/react-query'; -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'; -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'; - -const defaultSelect = { id: true } as const; - +import { useQuery } from "@tanstack/react-query"; +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"; +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"; +const defaultSelect = { + id: true +} as const; /** Query key factory - re-exported from query-keys.ts */ export const postsQueryKey = postKeys.list; - /** * Query hook for fetching Post list - * + * * @example * \`\`\`tsx * const { data, isLoading } = usePostsQuery({ @@ -1389,7 +1890,7 @@ export const postsQueryKey = postKeys.list; * }, * }); * \`\`\` - * + * * @example With scope for hierarchical cache invalidation * \`\`\`tsx * const { data } = usePostsQuery({ @@ -1398,29 +1899,53 @@ export const postsQueryKey = postKeys.list; * }); * \`\`\` */ -export function usePostsQuery> }>( - params: { selection: ({ fields: S } & Omit, 'fields'> & StrictSelect) } & Omit> }, Error, TData>, 'queryKey' | 'queryFn'> & { scope?: PostScope } -): UseQueryResult; -export function usePostsQuery> }>( - params?: { selection?: (Omit, 'fields'> & { fields?: undefined }) } & Omit> }, Error, TData>, 'queryKey' | 'queryFn'> & { scope?: PostScope } -): UseQueryResult; -export function usePostsQuery( - params?: { selection?: ListSelectionConfig } & 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?: Omit, "fields"> & { + fields?: undefined; + }; +} & Omit>; +}, Error, TData>, "queryKey" | "queryFn"> & { + scope?: PostScope; +}): UseQueryResult; +export function usePostsQuery(params?: { + selection?: ListSelectionConfig; +} & Omit, "queryKey" | "queryFn"> & { + scope?: PostScope; +}) { const selection = params?.selection; const args = buildListSelectionArgs(selection); - const { scope, selection: _selection, ...queryOptions } = params ?? {}; + const { + scope, + selection: _selection, + ...queryOptions + } = params ?? {}; void _selection; return useQuery({ queryKey: postKeys.list(args, scope), - queryFn: () => getClient().post.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(), - ...queryOptions, + queryFn: () => getClient().post.findMany({ + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as PostSelect + }).unwrap(), + ...queryOptions }); } - /** * Fetch Post list without React hooks - * + * * @example * \`\`\`ts * const data = await fetchPostsQuery({ @@ -1431,43 +1956,63 @@ export function usePostsQuery( * }); * \`\`\` */ -export async function fetchPostsQuery( - params: { selection: ({ fields: S } & Omit, 'fields'> & StrictSelect) } -): Promise<{ posts: ConnectionResult> }>; -export async function fetchPostsQuery( - params?: { selection?: (Omit, 'fields'> & { fields?: undefined }) } -): Promise<{ posts: ConnectionResult> }>; -export async function fetchPostsQuery( - params?: { selection?: ListSelectionConfig } -) { - const args = buildListSelectionArgs(params?.selection); - return getClient().post.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(); +export async function fetchPostsQuery(params: { + selection: { + fields: S; + } & Omit, "fields"> & StrictSelect; +}): Promise<{ + posts: ConnectionResult>; +}>; +export async function fetchPostsQuery(params?: { + selection?: Omit, "fields"> & { + fields?: undefined; + }; +}): Promise<{ + posts: ConnectionResult>; +}>; +export async function fetchPostsQuery(params?: { + selection?: ListSelectionConfig; +}) { + const args = buildListSelectionArgs(selection); + return getClient().post.findMany({ + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as PostSelect + }).unwrap(); } - /** * Prefetch Post list for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchPostsQuery(queryClient, { selection: { first: 10 } }); * \`\`\` */ -export async function prefetchPostsQuery( - queryClient: QueryClient, - params: { selection: ({ fields: S } & Omit, 'fields'> & StrictSelect) } & { scope?: PostScope } -): Promise; -export async function prefetchPostsQuery( - queryClient: QueryClient, - params?: { selection?: (Omit, 'fields'> & { fields?: undefined }) } & { scope?: PostScope } -): Promise; -export async function prefetchPostsQuery( - queryClient: QueryClient, - params?: { selection?: ListSelectionConfig } & { scope?: PostScope } -): Promise { - const args = buildListSelectionArgs(params?.selection); +export async function prefetchPostsQuery(queryClient: QueryClient, params: { + selection: { + fields: S; + } & Omit, "fields"> & StrictSelect; +} & { + scope?: PostScope; +}): Promise; +export async function prefetchPostsQuery(queryClient: QueryClient, params?: { + selection?: Omit, "fields"> & { + fields?: undefined; + }; +} & { + scope?: PostScope; +}): Promise; +export async function prefetchPostsQuery(queryClient: QueryClient, params?: { + selection?: ListSelectionConfig; +} & { + scope?: PostScope; +}): void { + const args = buildListSelectionArgs(selection); await queryClient.prefetchQuery({ queryKey: postKeys.list(args, params?.scope), - queryFn: () => getClient().post.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(), + queryFn: () => getClient().post.findMany({ + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as PostSelect + }).unwrap() }); } " @@ -1480,33 +2025,21 @@ exports[`Query Hook Generators generateListQueryHook generates list query hook w * DO NOT EDIT - changes will be overwritten */ -import { useQuery } from '@tanstack/react-query'; -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'; - -const defaultSelect = { id: true } as const; - -export const usersQueryKey = (variables?: FindManyArgs) => ['user', 'list', variables] as const; - +import { useQuery } from "@tanstack/react-query"; +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"; +const defaultSelect = { + id: true +} as const; +export const usersQueryKey = (variables?: FindManyArgs) => ["user", "list", variables] as const; /** * Query hook for fetching User list - * + * * @example * \`\`\`tsx * const { data, isLoading } = useUsersQuery({ @@ -1519,29 +2052,46 @@ export const usersQueryKey = (variables?: FindManyArgs> }>( - params: { selection: ({ fields: S } & Omit, 'fields'> & StrictSelect) } & Omit> }, Error, TData>, 'queryKey' | 'queryFn'> -): UseQueryResult; -export function useUsersQuery> }>( - params?: { selection?: (Omit, 'fields'> & { fields?: undefined }) } & Omit> }, Error, TData>, 'queryKey' | 'queryFn'> -): UseQueryResult; -export function useUsersQuery( - params?: { selection?: ListSelectionConfig } & Omit, 'queryKey' | 'queryFn'> -) { +export function useUsersQuery>; +}>(params: { + selection: { + fields: S; + } & Omit, "fields"> & StrictSelect; +} & Omit>; +}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; +export function useUsersQuery>; +}>(params?: { + selection?: Omit, "fields"> & { + fields?: undefined; + }; +} & Omit>; +}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; +export function useUsersQuery(params?: { + selection?: ListSelectionConfig; +} & Omit, "queryKey" | "queryFn">) { const selection = params?.selection; const args = buildListSelectionArgs(selection); - const { selection: _selection, ...queryOptions } = params ?? {}; + const { + selection: _selection, + ...queryOptions + } = params ?? {}; void _selection; return useQuery({ queryKey: usersQueryKey(args), - queryFn: () => getClient().user.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), - ...queryOptions, + queryFn: () => getClient().user.findMany({ + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(), + ...queryOptions }); } - /** * Fetch User list without React hooks - * + * * @example * \`\`\`ts * const data = await fetchUsersQuery({ @@ -1552,43 +2102,57 @@ export function useUsersQuery( * }); * \`\`\` */ -export async function fetchUsersQuery( - params: { selection: ({ fields: S } & Omit, 'fields'> & StrictSelect) } -): Promise<{ users: ConnectionResult> }>; -export async function fetchUsersQuery( - params?: { selection?: (Omit, 'fields'> & { fields?: undefined }) } -): Promise<{ users: ConnectionResult> }>; -export async function fetchUsersQuery( - params?: { selection?: ListSelectionConfig } -) { - const args = buildListSelectionArgs(params?.selection); - return getClient().user.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(); +export async function fetchUsersQuery(params: { + selection: { + fields: S; + } & Omit, "fields"> & StrictSelect; +}): Promise<{ + users: ConnectionResult>; +}>; +export async function fetchUsersQuery(params?: { + selection?: Omit, "fields"> & { + fields?: undefined; + }; +}): Promise<{ + users: ConnectionResult>; +}>; +export async function fetchUsersQuery(params?: { + selection?: ListSelectionConfig; +}) { + const args = buildListSelectionArgs(selection); + return getClient().user.findMany({ + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(); } - /** * Prefetch User list for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchUsersQuery(queryClient, { selection: { first: 10 } }); * \`\`\` */ -export async function prefetchUsersQuery( - queryClient: QueryClient, - params: { selection: ({ fields: S } & Omit, 'fields'> & StrictSelect) } -): Promise; -export async function prefetchUsersQuery( - queryClient: QueryClient, - params?: { selection?: (Omit, 'fields'> & { fields?: undefined }) } -): Promise; -export async function prefetchUsersQuery( - queryClient: QueryClient, - params?: { selection?: ListSelectionConfig } -): Promise { - const args = buildListSelectionArgs(params?.selection); +export async function prefetchUsersQuery(queryClient: QueryClient, params: { + selection: { + fields: S; + } & Omit, "fields"> & StrictSelect; +}): Promise; +export async function prefetchUsersQuery(queryClient: QueryClient, params?: { + selection?: Omit, "fields"> & { + fields?: undefined; + }; +}): Promise; +export async function prefetchUsersQuery(queryClient: QueryClient, params?: { + selection?: ListSelectionConfig; +}): void { + const args = buildListSelectionArgs(selection); await queryClient.prefetchQuery({ queryKey: usersQueryKey(args), - queryFn: () => getClient().user.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + queryFn: () => getClient().user.findMany({ + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap() }); } " @@ -1601,31 +2165,23 @@ exports[`Query Hook Generators generateSingleQueryHook generates single query ho * DO NOT EDIT - changes will be overwritten */ -import { useQuery } from '@tanstack/react-query'; -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'; -import type { - UserSelect, - UserWithRelations, -} from '../../orm/input-types'; -import type { - InferSelectResult, - StrictSelect, -} from '../../orm/select-types'; - -export type { UserSelect, UserWithRelations } from '../../orm/input-types'; - -const defaultSelect = { id: true } as const; - +import { useQuery } from "@tanstack/react-query"; +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"; +import type { UserSelect, UserWithRelations } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { UserSelect, UserWithRelations } from "../../orm/input-types"; +const defaultSelect = { + id: true +} as const; /** Query key factory - re-exported from query-keys.ts */ export const userQueryKey = userKeys.detail; - /** * Query hook for fetching a single User - * + * * @example * \`\`\`tsx * const { data, isLoading } = useUserQuery({ @@ -1634,28 +2190,49 @@ export const userQueryKey = userKeys.detail; * }); * \`\`\` */ -export function useUserQuery | null }>( - params: { id: string; selection: ({ fields: S } & StrictSelect) } & Omit | null }, Error, TData>, 'queryKey' | 'queryFn'> -): UseQueryResult; -export function useUserQuery | null }>( - params: { id: string; selection?: ({ fields?: undefined }) } & Omit | null }, Error, TData>, 'queryKey' | 'queryFn'> -): UseQueryResult; -export function useUserQuery( - params: { id: string; selection?: SelectionConfig } & Omit, 'queryKey' | 'queryFn'> -) { +export function useUserQuery | null; +}>(params: { + id: string; + selection: { + fields: S; + } & StrictSelect; +} & Omit | null; +}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; +export function useUserQuery | null; +}>(params: { + id: string; + selection?: { + fields?: undefined; + }; +} & 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 ?? {}; + const { + selection: _selection, + ...queryOptions + } = params ?? {}; void _selection; return useQuery({ queryKey: userKeys.detail(params.id), - queryFn: () => getClient().user.findOne({ id: params.id, ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), - ...queryOptions, + queryFn: () => getClient().user.findOne({ + id: params.id, + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(), + ...queryOptions }); } - /** * Fetch a single User without React hooks - * + * * @example * \`\`\`ts * const data = await fetchUserQuery({ @@ -1664,43 +2241,65 @@ export function useUserQuery( * }); * \`\`\` */ -export async function fetchUserQuery( - params: { id: string; selection: ({ fields: S } & StrictSelect) } -): Promise<{ user: InferSelectResult | null }>; -export async function fetchUserQuery( - params: { id: string; selection?: ({ fields?: undefined }) }, -): Promise<{ user: InferSelectResult | null }>; -export async function fetchUserQuery( - params: { id: string; selection?: SelectionConfig }, -) { +export async function fetchUserQuery(params: { + id: string; + selection: { + fields: S; + } & StrictSelect; +}): Promise<{ + user: InferSelectResult | null; +}>; +export async function fetchUserQuery(params: { + id: string; + selection?: { + fields?: undefined; + }; +}): 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, ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(); + return getClient().user.findOne({ + id: params.id, + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(); } - /** * Prefetch a single User for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchUserQuery(queryClient, { id: 'some-id' }); * \`\`\` */ -export async function prefetchUserQuery( - queryClient: QueryClient, - params: { id: string; selection: ({ fields: S } & StrictSelect) }, -): Promise; -export async function prefetchUserQuery( - queryClient: QueryClient, - params: { id: string; selection?: ({ fields?: undefined }) }, -): Promise; -export async function prefetchUserQuery( - queryClient: QueryClient, - params: { id: string; selection?: SelectionConfig }, -): 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?: { + fields?: undefined; + }; +}): Promise; +export async function prefetchUserQuery(queryClient: QueryClient, params: { + id: string; + selection?: SelectionConfig; +}): void { const args = buildSelectionArgs(params.selection); await queryClient.prefetchQuery({ queryKey: userKeys.detail(params.id), - queryFn: () => getClient().user.findOne({ id: params.id, ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + queryFn: () => getClient().user.findOne({ + id: params.id, + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap() }); } " @@ -1713,32 +2312,24 @@ exports[`Query Hook Generators generateSingleQueryHook generates single query ho * DO NOT EDIT - changes will be overwritten */ -import { useQuery } from '@tanstack/react-query'; -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'; -import type { - PostSelect, - PostWithRelations, -} from '../../orm/input-types'; -import type { - InferSelectResult, - StrictSelect, -} from '../../orm/select-types'; - -export type { PostSelect, PostWithRelations } from '../../orm/input-types'; - -const defaultSelect = { id: true } as const; - +import { useQuery } from "@tanstack/react-query"; +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"; +import type { PostSelect, PostWithRelations } from "../../orm/input-types"; +import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; +export type { PostSelect, PostWithRelations } from "../../orm/input-types"; +const defaultSelect = { + id: true +} as const; /** Query key factory - re-exported from query-keys.ts */ export const postQueryKey = postKeys.detail; - /** * Query hook for fetching a single Post - * + * * @example * \`\`\`tsx * const { data, isLoading } = usePostQuery({ @@ -1746,7 +2337,7 @@ export const postQueryKey = postKeys.detail; * selection: { fields: { id: true, name: true } }, * }); * \`\`\` - * + * * @example With scope for hierarchical cache invalidation * \`\`\`tsx * const { data } = usePostQuery({ @@ -1755,28 +2346,56 @@ export const postQueryKey = postKeys.detail; * }); * \`\`\` */ -export function usePostQuery | null }>( - params: { id: string; selection: ({ fields: S } & StrictSelect) } & Omit | null }, Error, TData>, 'queryKey' | 'queryFn'> & { scope?: PostScope } -): UseQueryResult; -export function usePostQuery | null }>( - params: { id: string; selection?: ({ fields?: undefined }) } & Omit | null }, Error, TData>, 'queryKey' | 'queryFn'> & { scope?: PostScope } -): UseQueryResult; -export function usePostQuery( - params: { id: string; selection?: SelectionConfig } & 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 | null; +}>(params: { + id: string; + selection?: { + fields?: undefined; + }; +} & 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 } = params ?? {}; + const { + scope, + selection: _selection, + ...queryOptions + } = params ?? {}; void _selection; return useQuery({ queryKey: postKeys.detail(params.id, scope), - queryFn: () => getClient().post.findOne({ id: params.id, ...(args ?? {}), select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(), - ...queryOptions, + queryFn: () => getClient().post.findOne({ + id: params.id, + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as PostSelect + }).unwrap(), + ...queryOptions }); } - /** * Fetch a single Post without React hooks - * + * * @example * \`\`\`ts * const data = await fetchPostQuery({ @@ -1785,43 +2404,71 @@ export function usePostQuery( * }); * \`\`\` */ -export async function fetchPostQuery( - params: { id: string; selection: ({ fields: S } & StrictSelect) } -): Promise<{ post: InferSelectResult | null }>; -export async function fetchPostQuery( - params: { id: string; selection?: ({ fields?: undefined }) }, -): Promise<{ post: InferSelectResult | null }>; -export async function fetchPostQuery( - params: { id: string; selection?: SelectionConfig }, -) { +export async function fetchPostQuery(params: { + id: string; + selection: { + fields: S; + } & StrictSelect; +}): Promise<{ + post: InferSelectResult | null; +}>; +export async function fetchPostQuery(params: { + id: string; + selection?: { + fields?: undefined; + }; +}): 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, ...(args ?? {}), select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(); + return getClient().post.findOne({ + id: params.id, + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as PostSelect + }).unwrap(); } - /** * Prefetch a single Post for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchPostQuery(queryClient, { id: 'some-id' }); * \`\`\` */ -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?: ({ fields?: undefined }) } & { scope?: PostScope }, -): Promise; -export async function prefetchPostQuery( - queryClient: QueryClient, - params: { id: string; selection?: SelectionConfig } & { scope?: PostScope }, -): 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?: { + fields?: undefined; + }; +} & { + scope?: PostScope; +}): Promise; +export async function prefetchPostQuery(queryClient: QueryClient, params: { + id: string; + selection?: SelectionConfig; +} & { + scope?: PostScope; +}): void { const args = buildSelectionArgs(params.selection); await queryClient.prefetchQuery({ - queryKey: postKeys.detail(params.id, params.scope), - queryFn: () => getClient().post.findOne({ id: params.id, ...(args ?? {}), select: (args?.select ?? defaultSelect) as PostSelect }).unwrap(), + queryKey: postKeys.detail(params.id, params?.scope), + queryFn: () => getClient().post.findOne({ + id: params.id, + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as PostSelect + }).unwrap() }); } " @@ -1834,29 +2481,21 @@ exports[`Query Hook Generators generateSingleQueryHook generates single query ho * DO NOT EDIT - changes will be overwritten */ -import { useQuery } from '@tanstack/react-query'; -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'; - -const defaultSelect = { id: true } as const; - -export const userQueryKey = (id: string) => ['user', 'detail', id] as const; - +import { useQuery } from "@tanstack/react-query"; +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"; +const defaultSelect = { + id: true +} as const; +export const userQueryKey = (id: string) => ["user", "detail", id] as const; /** * Query hook for fetching a single User - * + * * @example * \`\`\`tsx * const { data, isLoading } = useUserQuery({ @@ -1865,28 +2504,49 @@ export const userQueryKey = (id: string) => ['user', 'detail', id] as const; * }); * \`\`\` */ -export function useUserQuery | null }>( - params: { id: string; selection: ({ fields: S } & StrictSelect) } & Omit | null }, Error, TData>, 'queryKey' | 'queryFn'> -): UseQueryResult; -export function useUserQuery | null }>( - params: { id: string; selection?: ({ fields?: undefined }) } & Omit | null }, Error, TData>, 'queryKey' | 'queryFn'> -): UseQueryResult; -export function useUserQuery( - params: { id: string; selection?: SelectionConfig } & Omit, 'queryKey' | 'queryFn'> -) { +export function useUserQuery | null; +}>(params: { + id: string; + selection: { + fields: S; + } & StrictSelect; +} & Omit | null; +}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; +export function useUserQuery | null; +}>(params: { + id: string; + selection?: { + fields?: undefined; + }; +} & 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 ?? {}; + const { + selection: _selection, + ...queryOptions + } = params ?? {}; void _selection; return useQuery({ queryKey: userQueryKey(params.id), - queryFn: () => getClient().user.findOne({ id: params.id, ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), - ...queryOptions, + queryFn: () => getClient().user.findOne({ + id: params.id, + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(), + ...queryOptions }); } - /** * Fetch a single User without React hooks - * + * * @example * \`\`\`ts * const data = await fetchUserQuery({ @@ -1895,43 +2555,65 @@ export function useUserQuery( * }); * \`\`\` */ -export async function fetchUserQuery( - params: { id: string; selection: ({ fields: S } & StrictSelect) } -): Promise<{ user: InferSelectResult | null }>; -export async function fetchUserQuery( - params: { id: string; selection?: ({ fields?: undefined }) }, -): Promise<{ user: InferSelectResult | null }>; -export async function fetchUserQuery( - params: { id: string; selection?: SelectionConfig }, -) { +export async function fetchUserQuery(params: { + id: string; + selection: { + fields: S; + } & StrictSelect; +}): Promise<{ + user: InferSelectResult | null; +}>; +export async function fetchUserQuery(params: { + id: string; + selection?: { + fields?: undefined; + }; +}): 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, ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(); + return getClient().user.findOne({ + id: params.id, + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap(); } - /** * Prefetch a single User for SSR or cache warming - * + * * @example * \`\`\`ts * await prefetchUserQuery(queryClient, { id: 'some-id' }); * \`\`\` */ -export async function prefetchUserQuery( - queryClient: QueryClient, - params: { id: string; selection: ({ fields: S } & StrictSelect) }, -): Promise; -export async function prefetchUserQuery( - queryClient: QueryClient, - params: { id: string; selection?: ({ fields?: undefined }) }, -): Promise; -export async function prefetchUserQuery( - queryClient: QueryClient, - params: { id: string; selection?: SelectionConfig }, -): 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?: { + fields?: undefined; + }; +}): Promise; +export async function prefetchUserQuery(queryClient: QueryClient, params: { + id: string; + selection?: SelectionConfig; +}): void { const args = buildSelectionArgs(params.selection); await queryClient.prefetchQuery({ queryKey: userQueryKey(params.id), - queryFn: () => getClient().user.findOne({ id: params.id, ...(args ?? {}), select: (args?.select ?? defaultSelect) as UserSelect }).unwrap(), + queryFn: () => getClient().user.findOne({ + id: params.id, + ...(args ?? {}), + select: (args?.select ?? defaultSelect) as UserSelect + }).unwrap() }); } " diff --git a/graphql/codegen/src/core/codegen/client.ts b/graphql/codegen/src/core/codegen/client.ts index 483837da4..ed5727e96 100644 --- a/graphql/codegen/src/core/codegen/client.ts +++ b/graphql/codegen/src/core/codegen/client.ts @@ -1,58 +1,39 @@ /** * Client generator - generates client.ts as ORM client wrapper * - * Generates a configure()/getClient() singleton pattern that wraps the ORM client. - * React Query hooks use getClient() to delegate to ORM model methods. + * Uses template-copy pattern: reads hooks-client.ts from templates/ + * and writes it to the output directory with a generated file header. */ -import { getGeneratedFileHeader } from './utils'; - -/** - * Generate client.ts content - ORM client wrapper with configure/getClient - */ -export function generateClientFile(): string { - const header = getGeneratedFileHeader('ORM client wrapper for React Query hooks'); - - const code = ` -import { createClient } from '../orm'; -import type { OrmClientConfig } from '../orm/client'; +import * as fs from 'fs'; +import * as path from 'path'; -export type { OrmClientConfig } from '../orm/client'; -export type { GraphQLAdapter, GraphQLError, QueryResult } from '../orm/client'; -export { GraphQLRequestError } from '../orm/client'; +import { getGeneratedFileHeader } from './utils'; -type OrmClientInstance = ReturnType; -let client: OrmClientInstance | null = null; +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}` + ); +} -/** - * 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); +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; } /** - * Get the configured ORM client instance - * @throws Error if configure() has not been called + * Generate client.ts content - ORM client wrapper with configure/getClient */ -export function getClient(): OrmClientInstance { - if (!client) { - throw new Error( - 'ORM client not configured. Call configure() before using hooks.' - ); - } - return client; -} -`; - - return header + '\n' + code.trim() + '\n'; +export function generateClientFile(): string { + return readTemplateFile('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 dc28b3ea7..e5ceab809 100644 --- a/graphql/codegen/src/core/codegen/custom-mutations.ts +++ b/graphql/codegen/src/core/codegen/custom-mutations.ts @@ -1,5 +1,5 @@ /** - * 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.) @@ -13,14 +13,42 @@ * useRegisterMutation.ts * ... */ +import * as t from '@babel/types'; + import type { CleanOperation, TypeRegistry } from '../../types/schema'; +import { asConst } from './babel-ast'; +import { + buildDefaultSelectExpr, + buildSelectionArgsCall, + callExpr, + constDecl, + createFunctionParam, + createImportDeclaration, + createSTypeParam, + createTypeReExport, + customSelectResultTypeLiteral, + destructureParamsWithSelection, + exportDeclareFunction, + exportFunction, + generateHookFileCode, + getClientCustomCallUnwrap, + objectProp, + omitType, + returnUseMutation, + selectionConfigType, + spreadObj, + sRef, + typeofRef, + typeRef, + useMutationOptionsType, + useMutationResultType, + voidStatement +} from './hooks-ast'; import { - buildDefaultSelectLiteral, - getSelectTypeName, - wrapInferSelectResult + getSelectTypeName } from './select-helpers'; import { createTypeTracker, @@ -29,7 +57,7 @@ import { getTypeBaseName, typeRefToTsType } from './type-resolver'; -import { getGeneratedFileHeader,ucFirst } from './utils'; +import { ucFirst } from './utils'; export interface GeneratedCustomMutationFile { fileName: string; @@ -83,8 +111,7 @@ function generateCustomMutationHookInternal( const hasArgs = operation.args.length > 0; - // Resolve types using tracker for import tracking - const resultType = typeRefToTsType(operation.returnType, tracker); + typeRefToTsType(operation.returnType, tracker); for (const arg of operation.args) { typeRefToTsType(arg.type, tracker); } @@ -92,35 +119,29 @@ function generateCustomMutationHookInternal( const selectTypeName = getSelectTypeName(operation.returnType); const payloadTypeName = getTypeBaseName(operation.returnType); const hasSelect = !!selectTypeName && !!payloadTypeName; - const defaultSelectLiteral = - hasSelect && payloadTypeName - ? buildDefaultSelectLiteral(payloadTypeName, typeRegistry) - : null; - const lines: string[] = []; + const statements: t.Statement[] = []; // Imports - lines.push(`import { useMutation } from '@tanstack/react-query';`); - lines.push(`import type { UseMutationOptions, UseMutationResult } from '@tanstack/react-query';`); - lines.push(`import { getClient } from '../client';`); - lines.push(`import { buildSelectionArgs } from '../selection';`); - lines.push(`import type { SelectionConfig } from '../selection';`); + statements.push(createImportDeclaration('@tanstack/react-query', ['useMutation'])); + statements.push(createImportDeclaration('@tanstack/react-query', ['UseMutationOptions', 'UseMutationResult'], true)); + statements.push(createImportDeclaration('../client', ['getClient'])); + statements.push(createImportDeclaration('../selection', ['buildSelectionArgs'])); + statements.push(createImportDeclaration('../selection', ['SelectionConfig'], true)); if (useCentralizedKeys) { - lines.push(`import { customMutationKeys } from '../mutation-keys';`); + statements.push(createImportDeclaration('../mutation-keys', ['customMutationKeys'])); } - // ORM type imports - variable types come from orm/mutation, entity types from orm/input-types if (hasArgs) { - lines.push(`import type { ${varTypeName} } from '../../orm/mutation';`); + statements.push(createImportDeclaration('../../orm/mutation', [varTypeName], true)); } const inputTypeImports: string[] = []; if (hasSelect) { - inputTypeImports.push(selectTypeName); - inputTypeImports.push(payloadTypeName); + inputTypeImports.push(selectTypeName!); + inputTypeImports.push(payloadTypeName!); } else { - // For scalar/Connection returns, import any non-scalar type used in resultType for (const refType of tracker.referencedTypes) { if (!inputTypeImports.includes(refType)) { inputTypeImports.push(refType); @@ -128,104 +149,201 @@ function generateCustomMutationHookInternal( } } if (inputTypeImports.length > 0) { - lines.push(`import type { ${inputTypeImports.join(', ')} } from '../../orm/input-types';`); + statements.push(createImportDeclaration('../../orm/input-types', inputTypeImports, true)); } if (hasSelect) { - lines.push(`import type { InferSelectResult, StrictSelect } from '../../orm/select-types';`); + statements.push(createImportDeclaration('../../orm/select-types', ['InferSelectResult', 'StrictSelect'], true)); } - lines.push(''); - - // Re-export variable types for consumer convenience + // Re-exports if (hasArgs) { - lines.push(`export type { ${varTypeName} } from '../../orm/mutation';`); + statements.push(createTypeReExport([varTypeName], '../../orm/mutation')); } if (hasSelect) { - lines.push(`export type { ${selectTypeName} } from '../../orm/input-types';`); - } - if (hasArgs || hasSelect) { - lines.push(''); + statements.push(createTypeReExport([selectTypeName!], '../../orm/input-types')); } - if (hasSelect && defaultSelectLiteral) { - lines.push(`const defaultSelect = ${defaultSelectLiteral} as const;`); - lines.push(''); + // Default select + if (hasSelect) { + statements.push(constDecl('defaultSelect', asConst(buildDefaultSelectExpr(payloadTypeName!, typeRegistry)))); } // Hook if (hasSelect) { - // With selection.fields: overloaded hook for autocompletion + typed options/result - const mutationVarType = hasArgs ? varTypeName : 'void'; - const selectedResultType = (s: string) => - `{ ${operation.name}: ${wrapInferSelectResult(operation.returnType, payloadTypeName!, s)} }`; - const mutationOptionsType = (s: string) => - `Omit, 'mutationFn'>`; - const selectionWithFieldsType = (s: string) => - `({ fields: ${s} } & StrictSelect<${s}, ${selectTypeName}>)`; - const selectionWithoutFieldsType = () => `({ fields?: undefined })`; - - lines.push(`export function ${hookName}(`); - lines.push(` params: { selection: ${selectionWithFieldsType('S')} } & ${mutationOptionsType('S')}`); - lines.push(`): UseMutationResult<${selectedResultType('S')}, Error, ${mutationVarType}>;`); - lines.push(`export function ${hookName}(`); - lines.push(` params?: { selection?: ${selectionWithoutFieldsType()} } & ${mutationOptionsType('typeof defaultSelect')}`); - lines.push(`): UseMutationResult<${selectedResultType('typeof defaultSelect')}, Error, ${mutationVarType}>;`); - lines.push(`export function ${hookName}(`); - lines.push(` params?: { selection?: SelectionConfig<${selectTypeName}> } & Omit, 'mutationFn'>`); - lines.push(`) {`); - lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); - lines.push(` const { selection: _selection, ...mutationOptions } = params ?? {};`); - lines.push(` void _selection;`); - lines.push(` return useMutation({`); - - if (useCentralizedKeys) { - lines.push(` mutationKey: customMutationKeys.${operation.name}(),`); - } - + const mutationVarType: t.TSType = hasArgs ? typeRef(varTypeName) : t.tsVoidKeyword(); + + const selectedResultType = (sel: t.TSType) => + customSelectResultTypeLiteral(operation.name, operation.returnType, payloadTypeName!, sel); + + // 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) + ) + ); + + // Overload 2: without selection.fields + const o2SelectionProp = (() => { + const innerFieldsProp = t.tsPropertySignature( + t.identifier('fields'), + t.tsTypeAnnotation(t.tsUndefinedKeyword()) + ); + innerFieldsProp.optional = true; + const selProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(t.tsParenthesizedType(t.tsTypeLiteral([innerFieldsProp]))) + ); + selProp.optional = true; + return selProp; + })(); + const o2ParamType = t.tsIntersectionType([ + t.tsTypeLiteral([o2SelectionProp]), + useMutationOptionsType(selectedResultType(typeofRef('defaultSelect')), mutationVarType) + ]); + statements.push( + exportDeclareFunction( + hookName, + null, + [createFunctionParam('params', o2ParamType, true)], + useMutationResultType(selectedResultType(typeofRef('defaultSelect')), mutationVarType) + ) + ); + + // Implementation + const implSelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName!))) + ); + implSelProp.optional = true; + 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 selectExpr = t.tsAsExpression( + t.parenthesizedExpression( + t.logicalExpression( + '??', + t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), + t.identifier('defaultSelect') + ) + ), + typeRef(selectTypeName!) + ); + const selectObj = t.objectExpression([objectProp('select', selectExpr)]); + + let mutationFnExpr: t.Expression; if (hasArgs) { - lines.push(` mutationFn: (variables: ${varTypeName}) => getClient().mutation.${operation.name}(variables, { select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); + const variablesParam = createFunctionParam('variables', typeRef(varTypeName)); + mutationFnExpr = t.arrowFunctionExpression( + [variablesParam], + getClientCustomCallUnwrap('mutation', operation.name, [t.identifier('variables')], selectObj) + ); } else { - lines.push(` mutationFn: () => getClient().mutation.${operation.name}({ select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); + mutationFnExpr = t.arrowFunctionExpression( + [], + getClientCustomCallUnwrap('mutation', operation.name, [], selectObj) + ); } - lines.push(` ...mutationOptions,`); - lines.push(` });`); - lines.push(`}`); + body.push( + returnUseMutation( + mutationFnExpr, + [spreadObj(t.identifier('mutationOptions'))], + mutationKeyExpr + ) + ); + + statements.push(exportFunction(hookName, null, [createFunctionParam('params', implParamType, true)], body)); } else { // Without select: simple hook (scalar return type) - const resultTypeStr = `{ ${operation.name}: ${resultType} }`; - const mutationVarType = hasArgs ? varTypeName : 'void'; - - const optionsType = `Omit, 'mutationFn'>`; - + 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'] + ); + + const body: t.Statement[] = []; + body.push(constDecl('mutationOptions', t.logicalExpression('??', t.identifier('params'), t.objectExpression([])))); + + const mutationKeyExpr = useCentralizedKeys + ? callExpr( + t.memberExpression(t.identifier('customMutationKeys'), t.identifier(operation.name)), + [] + ) + : undefined; + + let mutationFnExpr: t.Expression; if (hasArgs) { - lines.push(`export function ${hookName}(`); - lines.push(` params?: ${optionsType}`); + const variablesParam = createFunctionParam('variables', typeRef(varTypeName)); + mutationFnExpr = t.arrowFunctionExpression( + [variablesParam], + getClientCustomCallUnwrap('mutation', operation.name, [t.identifier('variables')]) + ); } else { - lines.push(`export function ${hookName}(`); - lines.push(` params?: ${optionsType}`); - } - lines.push(`) {`); - lines.push(` const mutationOptions = params ?? {};`); - lines.push(` return useMutation({`); - - if (useCentralizedKeys) { - lines.push(` mutationKey: customMutationKeys.${operation.name}(),`); + mutationFnExpr = t.arrowFunctionExpression( + [], + getClientCustomCallUnwrap('mutation', operation.name, []) + ); } - if (hasArgs) { - lines.push(` mutationFn: (variables: ${varTypeName}) => getClient().mutation.${operation.name}(variables).unwrap(),`); - } else { - lines.push(` mutationFn: () => getClient().mutation.${operation.name}().unwrap(),`); - } + body.push( + returnUseMutation( + mutationFnExpr, + [spreadObj(t.identifier('mutationOptions'))], + mutationKeyExpr + ) + ); - lines.push(` ...mutationOptions,`); - lines.push(` });`); - lines.push(`}`); + statements.push(exportFunction(hookName, null, [createFunctionParam('params', optionsType, true)], body)); } - const content = getGeneratedFileHeader(`Custom mutation hook for ${operation.name}`) + '\n\n' + lines.join('\n') + '\n'; + const content = generateHookFileCode(`Custom mutation hook for ${operation.name}`, statements); return { fileName, diff --git a/graphql/codegen/src/core/codegen/custom-queries.ts b/graphql/codegen/src/core/codegen/custom-queries.ts index 18d11d483..b94eb1747 100644 --- a/graphql/codegen/src/core/codegen/custom-queries.ts +++ b/graphql/codegen/src/core/codegen/custom-queries.ts @@ -1,5 +1,5 @@ /** - * 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.) @@ -13,14 +13,48 @@ * useNodeQuery.ts * ... */ +import * as t from '@babel/types'; + import type { CleanOperation, TypeRegistry } from '../../types/schema'; +import { asConst } from './babel-ast'; +import { + addJSDocComment, + buildDefaultSelectExpr, + buildSelectionArgsCall, + callExpr, + constDecl, + createFunctionParam, + createImportDeclaration, + createSAndTDataTypeParams, + createSTypeParam, + createTDataTypeParam, + createTypeReExport, + customSelectResultTypeLiteral, + destructureParamsWithSelection, + exportAsyncDeclareFunction, + exportAsyncFunction, + exportDeclareFunction, + exportFunction, + generateHookFileCode, + getClientCustomCallUnwrap, + objectProp, + omitType, + returnUseQuery, + selectionConfigType, + spreadObj, + sRef, + typeofRef, + typeRef, + useQueryOptionsImplType, + useQueryOptionsType, + voidStatement, + wrapInferSelectResultType +} from './hooks-ast'; import { - buildDefaultSelectLiteral, - getSelectTypeName, - wrapInferSelectResult + getSelectTypeName } from './select-helpers'; import { createTypeTracker, @@ -31,7 +65,7 @@ import { isTypeRequired, typeRefToTsType } from './type-resolver'; -import { getGeneratedFileHeader,ucFirst } from './utils'; +import { ucFirst } from './utils'; export interface GeneratedCustomQueryFile { fileName: string; @@ -70,7 +104,6 @@ export function generateCustomQueryHook( const hasArgs = operation.args.length > 0; const hasRequiredArgs = operation.args.some((arg) => isTypeRequired(arg.type)); - // Resolve types using tracker for import tracking const resultType = typeRefToTsType(operation.returnType, tracker); for (const arg of operation.args) { typeRefToTsType(arg.type, tracker); @@ -79,41 +112,34 @@ export function generateCustomQueryHook( const selectTypeName = getSelectTypeName(operation.returnType); const payloadTypeName = getTypeBaseName(operation.returnType); const hasSelect = !!selectTypeName && !!payloadTypeName; - const defaultSelectLiteral = - hasSelect && payloadTypeName - ? buildDefaultSelectLiteral(payloadTypeName, typeRegistry) - : null; - const lines: string[] = []; + const statements: t.Statement[] = []; // Imports if (reactQueryEnabled) { - lines.push(`import { useQuery } from '@tanstack/react-query';`); - lines.push(`import type { UseQueryOptions, UseQueryResult, QueryClient } from '@tanstack/react-query';`); + statements.push(createImportDeclaration('@tanstack/react-query', ['useQuery'])); + statements.push(createImportDeclaration('@tanstack/react-query', ['UseQueryOptions', 'UseQueryResult', 'QueryClient'], true)); } - lines.push(`import { getClient } from '../client';`); - lines.push(`import { buildSelectionArgs } from '../selection';`); - lines.push(`import type { SelectionConfig } from '../selection';`); + statements.push(createImportDeclaration('../client', ['getClient'])); + statements.push(createImportDeclaration('../selection', ['buildSelectionArgs'])); + statements.push(createImportDeclaration('../selection', ['SelectionConfig'], true)); if (useCentralizedKeys) { - lines.push(`import { customQueryKeys } from '../query-keys';`); + statements.push(createImportDeclaration('../query-keys', ['customQueryKeys'])); } - // ORM type imports - variable types come from orm/query, entity types from orm/input-types if (hasArgs) { - lines.push(`import type { ${varTypeName} } from '../../orm/query';`); + statements.push(createImportDeclaration('../../orm/query', [varTypeName], true)); } const inputTypeImports: string[] = []; if (hasSelect) { - inputTypeImports.push(selectTypeName); - inputTypeImports.push(payloadTypeName); + inputTypeImports.push(selectTypeName!); + inputTypeImports.push(payloadTypeName!); } else { - // For scalar/Connection returns, import any non-scalar type used in resultType const baseName = getTypeBaseName(operation.returnType); if (baseName && !tracker.referencedTypes.has('__skip__')) { - // Import Connection types and other non-scalar types referenced in the result for (const refType of tracker.referencedTypes) { if (!inputTypeImports.includes(refType)) { inputTypeImports.push(refType); @@ -122,43 +148,101 @@ export function generateCustomQueryHook( } } if (inputTypeImports.length > 0) { - lines.push(`import type { ${inputTypeImports.join(', ')} } from '../../orm/input-types';`); + statements.push(createImportDeclaration('../../orm/input-types', inputTypeImports, true)); } if (hasSelect) { - lines.push(`import type { InferSelectResult, StrictSelect } from '../../orm/select-types';`); + statements.push(createImportDeclaration('../../orm/select-types', ['InferSelectResult', 'StrictSelect'], true)); } - lines.push(''); - - // Re-export variable types for consumer convenience + // Re-exports if (hasArgs) { - lines.push(`export type { ${varTypeName} } from '../../orm/query';`); + statements.push(createTypeReExport([varTypeName], '../../orm/query')); } if (hasSelect) { - lines.push(`export type { ${selectTypeName} } from '../../orm/input-types';`); - } - if (hasArgs || hasSelect) { - lines.push(''); + statements.push(createTypeReExport([selectTypeName!], '../../orm/input-types')); } - if (hasSelect && defaultSelectLiteral) { - lines.push(`const defaultSelect = ${defaultSelectLiteral} as const;`); - lines.push(''); + // Default select + if (hasSelect) { + statements.push(constDecl('defaultSelect', asConst(buildDefaultSelectExpr(payloadTypeName!, typeRegistry)))); } // Query key if (useCentralizedKeys) { - lines.push(`/** Query key factory - re-exported from query-keys.ts */`); - lines.push(`export const ${queryKeyName} = customQueryKeys.${operation.name};`); + const keyDecl = t.exportNamedDeclaration( + t.variableDeclaration('const', [ + t.variableDeclarator( + t.identifier(queryKeyName), + t.memberExpression(t.identifier('customQueryKeys'), t.identifier(operation.name)) + ) + ]) + ); + addJSDocComment(keyDecl, ['Query key factory - re-exported from query-keys.ts']); + statements.push(keyDecl); } else if (hasArgs) { - lines.push(`/** Query key factory for caching */`); - lines.push(`export const ${queryKeyName} = (variables?: ${varTypeName}) => ['${operation.name}', variables] as const;`); + 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 { - lines.push(`/** Query key factory for caching */`); - lines.push(`export const ${queryKeyName} = () => ['${operation.name}'] as const;`); + const keyFn = t.arrowFunctionExpression( + [], + asConst(t.arrayExpression([t.stringLiteral(operation.name)])) + ); + const keyDecl = t.exportNamedDeclaration( + t.variableDeclaration('const', [t.variableDeclarator(t.identifier(queryKeyName), keyFn)]) + ); + addJSDocComment(keyDecl, ['Query key factory for caching']); + statements.push(keyDecl); } - lines.push(''); + + // Helper to build select fallback expression + const buildSelectFallback = () => t.tsAsExpression( + t.parenthesizedExpression( + t.logicalExpression( + '??', + t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), + t.identifier('defaultSelect') + ) + ), + typeRef(selectTypeName!) + ); + + // 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!)]) + ]) + ); + + // Helper for { fields?: undefined } + const noFieldsType = () => { + const fp = t.tsPropertySignature(t.identifier('fields'), t.tsTypeAnnotation(t.tsUndefinedKeyword())); + fp.optional = true; + return t.tsParenthesizedType(t.tsTypeLiteral([fp])); + }; + + const selectedResultType = (sel: t.TSType) => + customSelectResultTypeLiteral(operation.name, operation.returnType, payloadTypeName!, sel); // Hook if (reactQueryEnabled) { @@ -166,125 +250,204 @@ export function generateCustomQueryHook( const argNames = operation.args.map((a) => a.name).join(', '); const exampleCall = hasArgs ? `${hookName}({ ${argNames} })` : `${hookName}()`; - lines.push(`/**`); - lines.push(` * ${description}`); - lines.push(` *`); - lines.push(` * @example`); - lines.push(` * \`\`\`tsx`); - lines.push(` * const { data, isLoading } = ${exampleCall};`); - lines.push(` *`); - lines.push(` * if (data?.${operation.name}) {`); - lines.push(` * console.log(data.${operation.name});`); - lines.push(` * }`); - lines.push(` * \`\`\``); - lines.push(` */`); - if (hasSelect) { - // With selection.fields: overloaded hook for autocompletion - const customSelectResultType = (s: string) => - `{ ${operation.name}: ${wrapInferSelectResult(operation.returnType, payloadTypeName!, s)} }`; - const optionsType = (queryData: string, data: string) => - `Omit, 'queryKey' | 'queryFn'>`; - - const withFieldsSelectionType = (s: string) => - `({ fields: ${s} } & StrictSelect<${s}, ${selectTypeName}>)`; - const withoutFieldsSelectionType = () => `({ fields?: undefined })`; - // Overload 1: with selection.fields + const o1Props: t.TSPropertySignature[] = []; if (hasArgs) { - const varTypeStr = hasRequiredArgs ? varTypeName : `${varTypeName} | undefined`; - lines.push(`export function ${hookName}(`); - lines.push(` params: { variables: ${varTypeStr}; selection: ${withFieldsSelectionType('S')} } & ${optionsType(customSelectResultType('S'), 'TData')}`); - lines.push(`): UseQueryResult;`); - } else { - lines.push(`export function ${hookName}(`); - lines.push(` params: { selection: ${withFieldsSelectionType('S')} } & ${optionsType(customSelectResultType('S'), 'TData')}`); - lines.push(`): UseQueryResult;`); + const varType = hasRequiredArgs + ? typeRef(varTypeName) + : t.tsUnionType([typeRef(varTypeName), t.tsUndefinedKeyword()]); + o1Props.push(t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(varType))); } - - // Overload 2: without selection.fields (uses default) + 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); + + // Overload 2: without fields + const o2Props: t.TSPropertySignature[] = []; if (hasArgs) { - lines.push(`export function ${hookName}(`); - lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}; selection?: ${withoutFieldsSelectionType()} } & ${optionsType(customSelectResultType('typeof defaultSelect'), 'TData')}`); - lines.push(`): UseQueryResult;`); - } else { - lines.push(`export function ${hookName}(`); - lines.push(` params?: { selection?: ${withoutFieldsSelectionType()} } & ${optionsType(customSelectResultType('typeof defaultSelect'), 'TData')}`); - lines.push(`): UseQueryResult;`); + const varProp = t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(typeRef(varTypeName))); + if (!hasRequiredArgs) varProp.optional = true; + o2Props.push(varProp); } + const selProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(noFieldsType())); + selProp.optional = true; + o2Props.push(selProp); + const o2ParamType = t.tsIntersectionType([ + t.tsTypeLiteral(o2Props), + omitType(typeRef('UseQueryOptions', [selectedResultType(typeofRef('defaultSelect')), typeRef('Error'), typeRef('TData')]), ['queryKey', 'queryFn']) + ]); + const o2Param = createFunctionParam('params', o2ParamType, !hasRequiredArgs); + statements.push( + exportDeclareFunction( + hookName, + createTDataTypeParam(selectedResultType(typeofRef('defaultSelect'))), + [o2Param], + typeRef('UseQueryResult', [typeRef('TData')]) + ) + ); // Implementation + const implProps: t.TSPropertySignature[] = []; if (hasArgs) { - lines.push(`export function ${hookName}(`); - lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}; selection?: SelectionConfig<${selectTypeName}> } & Omit, 'queryKey' | 'queryFn'>`); - lines.push(`) {`); - lines.push(` const variables = params?.variables;`); - lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); - lines.push(` const { variables: _variables, selection: _selection, ...queryOptions } = params ?? {};`); - lines.push(` void _variables;`); - lines.push(` void _selection;`); - lines.push(` return useQuery({`); - lines.push(` queryKey: ${queryKeyName}(variables),`); - lines.push(` queryFn: () => getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}, { select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - if (hasRequiredArgs) { - lines.push(` enabled: !!variables && params?.enabled !== false,`); - } - lines.push(` ...queryOptions,`); - lines.push(` });`); - lines.push(`}`); - } else { - lines.push(`export function ${hookName}(`); - lines.push(` params?: { selection?: SelectionConfig<${selectTypeName}> } & Omit, 'queryKey' | 'queryFn'>`); - lines.push(`) {`); - lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); - lines.push(` const { selection: _selection, ...queryOptions } = params ?? {};`); - lines.push(` void _selection;`); - lines.push(` return useQuery({`); - lines.push(` queryKey: ${queryKeyName}(),`); - lines.push(` queryFn: () => getClient().query.${operation.name}({ select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - lines.push(` ...queryOptions,`); - lines.push(` });`); - lines.push(`}`); + const varProp = t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(typeRef(varTypeName))); + if (!hasRequiredArgs) varProp.optional = true; + implProps.push(varProp); } - } else { - // Without select: simple hook (scalar return type) - const resultTypeStr = `{ ${operation.name}: ${resultType} }`; - const optionsType = `Omit, 'queryKey' | 'queryFn'>`; - - lines.push(`export function ${hookName}(`); + const implSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName!)))); + implSelProp.optional = true; + implProps.push(implSelProp); + const implParamType = t.tsIntersectionType([ + t.tsTypeLiteral(implProps), + useQueryOptionsImplType() + ]); + const implParam = createFunctionParam('params', implParamType, !hasRequiredArgs); + + const body: t.Statement[] = []; if (hasArgs) { - lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName} } & ${optionsType}`); - } else { - lines.push(` params?: ${optionsType}`); + body.push(constDecl('variables', t.optionalMemberExpression(t.identifier('params'), t.identifier('variables'), false, true))); } - lines.push(`): UseQueryResult {`); + body.push(buildSelectionArgsCall(selectTypeName!)); + if (hasArgs) { - lines.push(` const variables = params?.variables;`); - lines.push(` const { variables: _variables, ...queryOptions } = params ?? {};`); - lines.push(` void _variables;`); + const destructPattern = t.objectPattern([ + t.objectProperty(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 { - lines.push(` const queryOptions = params ?? {};`); + body.push(destructureParamsWithSelection('queryOptions')); + body.push(voidStatement('_selection')); } - lines.push(` return useQuery({`); + const selectObj = t.objectExpression([objectProp('select', buildSelectFallback())]); + const queryFnArgs = hasArgs + ? [hasRequiredArgs ? t.tsNonNullExpression(t.identifier('variables')) : t.identifier('variables'), selectObj] + : [selectObj]; + 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) { - lines.push(` queryKey: ${queryKeyName}(variables),`); - lines.push(` queryFn: () => getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}).unwrap(),`); + const varProp = t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(typeRef(varTypeName))); + if (!hasRequiredArgs) varProp.optional = true; + paramType = t.tsIntersectionType([t.tsTypeLiteral([varProp]), optType]); } else { - lines.push(` queryKey: ${queryKeyName}(),`); - lines.push(` queryFn: () => getClient().query.${operation.name}().unwrap(),`); + paramType = optType; } - if (hasRequiredArgs) { - lines.push(` enabled: !!variables && params?.enabled !== false,`); + 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', t.optionalMemberExpression(t.identifier('params'), t.identifier('variables'), false, true))); + 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([])))); } - lines.push(` ...queryOptions,`); - lines.push(` });`); - lines.push(`}`); + const queryFnArgs = hasArgs + ? [hasRequiredArgs ? t.tsNonNullExpression(t.identifier('variables')) : t.identifier('variables')] + : []; + const queryFnExpr = t.arrowFunctionExpression( + [], + getClientCustomCallUnwrap('query', operation.name, queryFnArgs as t.Expression[]) + ); + + 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, null, [implParam], body, typeRef('UseQueryResult', [typeRef('TData')]))); } - - lines.push(''); } // Fetch function (non-hook) @@ -292,160 +455,243 @@ export function generateCustomQueryHook( const fetchArgNames = operation.args.map((a) => a.name).join(', '); const fetchExampleCall = hasArgs ? `${fetchFnName}({ ${fetchArgNames} })` : `${fetchFnName}()`; - lines.push(`/**`); - lines.push(` * Fetch ${operation.name} without React hooks`); - lines.push(` *`); - lines.push(` * @example`); - lines.push(` * \`\`\`ts`); - lines.push(` * const data = await ${fetchExampleCall};`); - lines.push(` * \`\`\``); - lines.push(` */`); - if (hasSelect) { - const customSelectResultType = (s: string) => - `{ ${operation.name}: ${wrapInferSelectResult(operation.returnType, payloadTypeName!, s)} }`; - const withFieldsSelectionType = (s: string) => - `({ fields: ${s} } & StrictSelect<${s}, ${selectTypeName}>)`; - const withoutFieldsSelectionType = () => `({ fields?: undefined })`; + // Overload 1: with fields + const f1Props: t.TSPropertySignature[] = []; + if (hasArgs) { + const varType = hasRequiredArgs ? typeRef(varTypeName) : t.tsUnionType([typeRef(varTypeName), t.tsUndefinedKeyword()]); + f1Props.push(t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(varType))); + } + f1Props.push(t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(fieldsSelectionType(sRef())))); + const f1Decl = exportAsyncDeclareFunction( + fetchFnName, + createSTypeParam(selectTypeName!), + [createFunctionParam('params', t.tsTypeLiteral(f1Props))], + typeRef('Promise', [selectedResultType(sRef())]) + ); + addJSDocComment(f1Decl, [ + `Fetch ${operation.name} without React hooks`, + '', + '@example', + '```ts', + `const data = await ${fetchExampleCall};`, + '```' + ]); + statements.push(f1Decl); + + // Overload 2: without fields + const f2Props: t.TSPropertySignature[] = []; + if (hasArgs) { + const varProp = t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(typeRef(varTypeName))); + if (!hasRequiredArgs) varProp.optional = true; + f2Props.push(varProp); + } + const f2SelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(noFieldsType())); + f2SelProp.optional = true; + f2Props.push(f2SelProp); + statements.push( + exportAsyncDeclareFunction( + fetchFnName, + null, + [createFunctionParam('params', t.tsTypeLiteral(f2Props), !hasRequiredArgs)], + typeRef('Promise', [selectedResultType(typeofRef('defaultSelect'))]) + ) + ); + // Implementation + const fImplProps: t.TSPropertySignature[] = []; if (hasArgs) { - const requiredVarType = hasRequiredArgs ? varTypeName : `${varTypeName} | undefined`; - - lines.push(`export async function ${fetchFnName}(`); - lines.push(` params: { variables: ${requiredVarType}; selection: ${withFieldsSelectionType('S')} }`); - lines.push(`): Promise<${customSelectResultType('S')}>;`); - lines.push(`export async function ${fetchFnName}(`); - lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}; selection?: ${withoutFieldsSelectionType()} }`); - lines.push(`): Promise<${customSelectResultType('typeof defaultSelect')}>;`); - lines.push(`export async function ${fetchFnName}(`); - lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}; selection?: SelectionConfig<${selectTypeName}> },`); - lines.push(`) {`); - lines.push(` const variables = params?.variables;`); - lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); - lines.push(` return getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}, { select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap();`); - lines.push(`}`); - } else { - lines.push(`export async function ${fetchFnName}(`); - lines.push(` params: { selection: ${withFieldsSelectionType('S')} }`); - lines.push(`): Promise<${customSelectResultType('S')}>;`); - lines.push(`export async function ${fetchFnName}(`); - lines.push(` params?: { selection?: ${withoutFieldsSelectionType()} },`); - lines.push(`): Promise<${customSelectResultType('typeof defaultSelect')}>;`); - lines.push(`export async function ${fetchFnName}(`); - lines.push(` params?: { selection?: SelectionConfig<${selectTypeName}> },`); - lines.push(`) {`); - lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); - lines.push(` return getClient().query.${operation.name}({ select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap();`); - lines.push(`}`); + 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!)))); + fImplSelProp.optional = true; + fImplProps.push(fImplSelProp); + + const fBody: t.Statement[] = []; + if (hasArgs) { + fBody.push(constDecl('variables', t.optionalMemberExpression(t.identifier('params'), t.identifier('variables'), false, true))); } + fBody.push(buildSelectionArgsCall(selectTypeName!)); + const selectObj = t.objectExpression([objectProp('select', buildSelectFallback())]); + const fCallArgs = hasArgs + ? [hasRequiredArgs ? t.tsNonNullExpression(t.identifier('variables')) : t.identifier('variables'), selectObj] + : [selectObj]; + fBody.push(t.returnStatement(getClientCustomCallUnwrap('query', operation.name, fCallArgs as t.Expression[]))); + statements.push(exportAsyncFunction(fetchFnName, null, [createFunctionParam('params', t.tsTypeLiteral(fImplProps), !hasRequiredArgs)], fBody)); } else { + const fBody: t.Statement[] = []; if (hasArgs) { - lines.push(`export async function ${fetchFnName}(`); - lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName} }`); - lines.push(`) {`); - lines.push(` const variables = params?.variables;`); - lines.push(` return getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}).unwrap();`); - lines.push(`}`); + 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', t.optionalMemberExpression(t.identifier('params'), t.identifier('variables'), false, true))); + 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 { - lines.push(`export async function ${fetchFnName}() {`); - lines.push(` return getClient().query.${operation.name}().unwrap();`); - lines.push(`}`); + 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); } } // Prefetch function if (reactQueryEnabled) { - lines.push(''); - const prefetchFnName = `prefetch${ucFirst(operation.name)}Query`; const prefetchArgNames = operation.args.map((a) => a.name).join(', '); const prefetchExampleCall = hasArgs ? `${prefetchFnName}(queryClient, { ${prefetchArgNames} })` : `${prefetchFnName}(queryClient)`; - lines.push(`/**`); - lines.push(` * Prefetch ${operation.name} for SSR or cache warming`); - lines.push(` *`); - lines.push(` * @example`); - lines.push(` * \`\`\`ts`); - lines.push(` * await ${prefetchExampleCall};`); - lines.push(` * \`\`\``); - lines.push(` */`); - if (hasSelect) { - const withFieldsSelectionType = (s: string) => - `({ fields: ${s} } & StrictSelect<${s}, ${selectTypeName}>)`; - const withoutFieldsSelectionType = () => `({ fields?: undefined })`; + // 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())))); + const p1Decl = exportAsyncDeclareFunction( + prefetchFnName, + createSTypeParam(selectTypeName!), + [createFunctionParam('queryClient', typeRef('QueryClient')), createFunctionParam('params', t.tsTypeLiteral(p1Props))], + typeRef('Promise', [t.tsVoidKeyword()]) + ); + addJSDocComment(p1Decl, [ + `Prefetch ${operation.name} for SSR or cache warming`, + '', + '@example', + '```ts', + `await ${prefetchExampleCall};`, + '```' + ]); + statements.push(p1Decl); + + // Overload 2: without fields + const p2Props: t.TSPropertySignature[] = []; + if (hasArgs) { + const varProp = t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(typeRef(varTypeName))); + if (!hasRequiredArgs) varProp.optional = true; + p2Props.push(varProp); + } + const p2SelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(noFieldsType())); + p2SelProp.optional = true; + p2Props.push(p2SelProp); + statements.push( + exportAsyncDeclareFunction( + prefetchFnName, + null, + [createFunctionParam('queryClient', typeRef('QueryClient')), createFunctionParam('params', t.tsTypeLiteral(p2Props), !hasRequiredArgs)], + typeRef('Promise', [t.tsVoidKeyword()]) + ) + ); + // Implementation + const pImplProps: t.TSPropertySignature[] = []; if (hasArgs) { - const requiredVarType = hasRequiredArgs ? varTypeName : `${varTypeName} | undefined`; - - lines.push(`export async function ${prefetchFnName}(`); - lines.push(` queryClient: QueryClient,`); - lines.push(` params: { variables: ${requiredVarType}; selection: ${withFieldsSelectionType('S')} }`); - lines.push(`): Promise;`); - lines.push(`export async function ${prefetchFnName}(`); - lines.push(` queryClient: QueryClient,`); - lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}; selection?: ${withoutFieldsSelectionType()} }`); - lines.push(`): Promise;`); - lines.push(`export async function ${prefetchFnName}(`); - lines.push(` queryClient: QueryClient,`); - lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName}; selection?: SelectionConfig<${selectTypeName}> }`); - lines.push(`): Promise {`); - lines.push(` const variables = params?.variables;`); - lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); - lines.push(` await queryClient.prefetchQuery({`); - lines.push(` queryKey: ${queryKeyName}(variables),`); - lines.push(` queryFn: () => getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}, { select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - lines.push(` });`); - lines.push(`}`); - } else { - lines.push(`export async function ${prefetchFnName}(`); - lines.push(` queryClient: QueryClient,`); - lines.push(` params: { selection: ${withFieldsSelectionType('S')} }`); - lines.push(`): Promise;`); - lines.push(`export async function ${prefetchFnName}(`); - lines.push(` queryClient: QueryClient,`); - lines.push(` params?: { selection?: ${withoutFieldsSelectionType()} }`); - lines.push(`): Promise;`); - lines.push(`export async function ${prefetchFnName}(`); - lines.push(` queryClient: QueryClient,`); - lines.push(` params?: { selection?: SelectionConfig<${selectTypeName}> }`); - lines.push(`): Promise {`); - lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); - lines.push(` await queryClient.prefetchQuery({`); - lines.push(` queryKey: ${queryKeyName}(),`); - lines.push(` queryFn: () => getClient().query.${operation.name}({ select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - lines.push(` });`); - lines.push(`}`); + 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!)))); + pImplSelProp.optional = true; + pImplProps.push(pImplSelProp); + + const pBody: t.Statement[] = []; + if (hasArgs) { + pBody.push(constDecl('variables', t.optionalMemberExpression(t.identifier('params'), t.identifier('variables'), false, true))); + } + pBody.push(buildSelectionArgsCall(selectTypeName!)); + const selectObj = t.objectExpression([objectProp('select', buildSelectFallback())]); + const pCallArgs = hasArgs + ? [hasRequiredArgs ? t.tsNonNullExpression(t.identifier('variables')) : t.identifier('variables'), selectObj] + : [selectObj]; + 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), !hasRequiredArgs)], + pBody, + t.tsVoidKeyword() + ) + ); } else { + // Without select + const pBody: t.Statement[] = []; + const pParams: t.Identifier[] = [createFunctionParam('queryClient', typeRef('QueryClient'))]; + if (hasArgs) { - lines.push(`export async function ${prefetchFnName}(`); - lines.push(` queryClient: QueryClient,`); - lines.push(` params${hasRequiredArgs ? '' : '?'}: { variables${hasRequiredArgs ? '' : '?'}: ${varTypeName} }`); - lines.push(`): Promise {`); - lines.push(` const variables = params?.variables;`); - lines.push(` await queryClient.prefetchQuery({`); - lines.push(` queryKey: ${queryKeyName}(variables),`); - lines.push(` queryFn: () => getClient().query.${operation.name}(${hasRequiredArgs ? 'variables!' : 'variables'}).unwrap(),`); - lines.push(` });`); - lines.push(`}`); + 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', t.optionalMemberExpression(t.identifier('params'), t.identifier('variables'), false, true))); + 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 { - lines.push(`export async function ${prefetchFnName}(queryClient: QueryClient): Promise {`); - lines.push(` await queryClient.prefetchQuery({`); - lines.push(` queryKey: ${queryKeyName}(),`); - lines.push(` queryFn: () => getClient().query.${operation.name}().unwrap(),`); - lines.push(` });`); - lines.push(`}`); + 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 pDecl = exportAsyncFunction(prefetchFnName, null, pParams, pBody, t.tsVoidKeyword()); + addJSDocComment(pDecl, [ + `Prefetch ${operation.name} for SSR or cache warming`, + '', + '@example', + '```ts', + `await ${prefetchExampleCall};`, + '```' + ]); + statements.push(pDecl); } } const headerText = reactQueryEnabled ? `Custom query hook for ${operation.name}` : `Custom query functions for ${operation.name}`; - const content = getGeneratedFileHeader(headerText) + '\n\n' + lines.join('\n') + '\n'; + const content = generateHookFileCode(headerText, statements); return { fileName, 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..6b3782f43 --- /dev/null +++ b/graphql/codegen/src/core/codegen/hooks-ast.ts @@ -0,0 +1,874 @@ +/** + * 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, TypeRegistry } from '../../types/schema'; +import { commentBlock, generateCode } from './babel-ast'; +import { getTypeBaseName, 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 withoutFieldsSelectionType(): t.TSTypeLiteral { + return typeLiteralWithProps([{ + name: 'fields', + type: t.tsUndefinedKeyword(), + optional: true + }]); +} + +export function withoutFieldsListSelectionType( + selectTypeName: string, + filterTypeName: string, + orderByTypeName: string +): t.TSIntersectionType { + return t.tsIntersectionType([ + omitType( + listSelectionConfigType(typeRef(selectTypeName), filterTypeName, orderByTypeName), + ['fields'] + ), + withoutFieldsSelectionType() + ]); +} + +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 buildSelectFallbackExpr( + argsIdent: string, + defaultSelectIdent: string, + selectTypeName: string +): t.TSAsExpression { + return t.tsAsExpression( + t.parenthesizedExpression( + t.logicalExpression( + '??', + t.optionalMemberExpression( + t.identifier(argsIdent), + t.identifier('select'), + false, + true + ), + t.identifier(defaultSelectIdent) + ) + ), + typeRef(selectTypeName) + ); +} + +export function buildFindManyCallExpr( + singularName: string, + argsIdent: string, + selectTypeName: string, + defaultSelectIdent: string = 'defaultSelect' +): t.CallExpression { + const spreadArgs = t.parenthesizedExpression( + t.logicalExpression('??', t.identifier(argsIdent), t.objectExpression([])) + ); + return getClientCallUnwrap( + singularName, + 'findMany', + t.objectExpression([ + t.spreadElement(spreadArgs), + objectProp('select', buildSelectFallbackExpr(argsIdent, defaultSelectIdent, selectTypeName)) + ]) + ); +} + +export function buildFindOneCallExpr( + singularName: string, + pkFieldName: string, + argsIdent: string, + selectTypeName: string, + paramsIdent: string = 'params', + defaultSelectIdent: string = 'defaultSelect' +): t.CallExpression { + return getClientCallUnwrap( + singularName, + 'findOne', + t.objectExpression([ + objectProp( + pkFieldName, + t.memberExpression(t.identifier(paramsIdent), t.identifier(pkFieldName)) + ), + t.spreadElement( + t.parenthesizedExpression( + t.logicalExpression('??', t.identifier(argsIdent), t.objectExpression([])) + ) + ), + objectProp('select', buildSelectFallbackExpr(argsIdent, defaultSelectIdent, selectTypeName)) + ]) + ); +} + +// ============================================================================ +// 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) +// ============================================================================ + +const NON_SELECT_TYPES_AST = new Set([ + 'String', 'Int', 'Float', 'Boolean', 'ID', + 'BigFloat', 'BigInt', 'Cursor', 'Date', 'Datetime', + 'JSON', 'UUID', 'Uuid', 'Time', + 'Query', 'Mutation' +]); + +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 buildDefaultSelectExpr( + typeName: string, + typeRegistry: TypeRegistry, + depth: number = 0 +): t.ObjectExpression { + const resolved = typeRegistry.get(typeName); + const fields = resolved?.fields ?? []; + + if (depth > 3 || fields.length === 0) { + const fieldName = fields.length > 0 ? fields[0].name : 'id'; + return t.objectExpression([objectProp(fieldName, t.booleanLiteral(true))]); + } + + const idLike = fields.find((f) => f.name === 'id' || f.name === 'nodeId'); + if (idLike) return t.objectExpression([objectProp(idLike.name, t.booleanLiteral(true))]); + + const scalarField = fields.find((f) => { + const baseName = getTypeBaseName(f.type); + if (!baseName) return false; + if (NON_SELECT_TYPES_AST.has(baseName)) return true; + return typeRegistry.get(baseName)?.kind === 'ENUM'; + }); + if (scalarField) return t.objectExpression([objectProp(scalarField.name, t.booleanLiteral(true))]); + + const first = fields[0]; + const firstBase = getTypeBaseName(first.type); + if ( + !firstBase || + NON_SELECT_TYPES_AST.has(firstBase) || + typeRegistry.get(firstBase)?.kind === 'ENUM' + ) { + return t.objectExpression([objectProp(first.name, t.booleanLiteral(true))]); + } + + const nested = buildDefaultSelectExpr(firstBase, typeRegistry, depth + 1); + return t.objectExpression([ + objectProp(first.name, t.objectExpression([objectProp('select', nested)])) + ]); +} + +export function buildSelectionArgsCall( + selectTypeName: string +): t.VariableDeclaration { + const call = t.callExpression(t.identifier('buildSelectionArgs'), [ + t.optionalMemberExpression( + t.identifier('params'), + t.identifier('selection'), + false, + true + ) + ]); + // @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.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/mutations.ts b/graphql/codegen/src/core/codegen/mutations.ts index 078521e49..1edbbe07a 100644 --- a/graphql/codegen/src/core/codegen/mutations.ts +++ b/graphql/codegen/src/core/codegen/mutations.ts @@ -1,5 +1,5 @@ /** - * Mutation hook generators - delegates to ORM model methods + * Mutation hook generators - delegates to ORM model methods (Babel AST-based) * * Output structure: * mutations/ @@ -7,7 +7,39 @@ * useUpdateCarMutation.ts -> ORM update * useDeleteCarMutation.ts -> ORM delete */ +import * as t from '@babel/types'; + import type { CleanTable } from '../../types/schema'; +import { asConst } from './babel-ast'; +import { + addJSDocComment, + buildSelectionArgsCall, + callExpr, + constDecl, + createFunctionParam, + createImportDeclaration, + createSTypeParam, + createTypeReExport, + destructureParamsWithSelection, + exportDeclareFunction, + exportFunction, + generateHookFileCode, + getClientCallUnwrap, + inferSelectResultType, + objectProp, + omitType, + returnUseMutation, + selectionConfigType, + shorthandProp, + spreadObj, + sRef, + typeofRef, + typeRef, + typeLiteralWithProps, + useMutationOptionsType, + useMutationResultType, + voidStatement +} from './hooks-ast'; import { getCreateMutationFileName, getCreateMutationHookName, @@ -16,7 +48,6 @@ import { getDeleteMutationFileName, getDeleteMutationHookName, getDeleteMutationName, - getGeneratedFileHeader, getPrimaryKeyInfo, getTableNames, getUpdateMutationFileName, @@ -36,6 +67,49 @@ export interface MutationGeneratorOptions { useCentralizedKeys?: boolean; } +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 buildSelectFallback(selectTypeName: string): t.TSAsExpression { + return t.tsAsExpression( + t.parenthesizedExpression( + t.logicalExpression( + '??', + t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), + t.identifier('defaultSelect') + ) + ), + typeRef(selectTypeName) + ); +} + +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)]) + ]) + ); +} + +function buildNoFieldsType(): t.TSParenthesizedType { + const fp = t.tsPropertySignature(t.identifier('fields'), t.tsTypeAnnotation(t.tsUndefinedKeyword())); + fp.optional = true; + return t.tsParenthesizedType(t.tsTypeLiteral([fp])); +} + export function generateCreateMutationHook( table: CleanTable, options: MutationGeneratorOptions = {} @@ -45,9 +119,7 @@ export function generateCreateMutationHook( useCentralizedKeys = true } = options; - if (!reactQueryEnabled) { - return null; - } + if (!reactQueryEnabled) return null; const { typeName, singularName } = getTableNames(table); const hookName = getCreateMutationHookName(table); @@ -57,93 +129,143 @@ export function generateCreateMutationHook( const selectTypeName = `${typeName}Select`; const relationTypeName = `${typeName}WithRelations`; const createInputTypeName = `Create${typeName}Input`; - const defaultFieldName = getDefaultSelectFieldName(table); - const lines: string[] = []; + const statements: t.Statement[] = []; // Imports - lines.push(`import { useMutation, useQueryClient } from '@tanstack/react-query';`); - lines.push(`import type { UseMutationOptions, UseMutationResult } from '@tanstack/react-query';`); - lines.push(`import { getClient } from '../client';`); - lines.push(`import { buildSelectionArgs } from '../selection';`); - lines.push(`import type { SelectionConfig } from '../selection';`); - - if (useCentralizedKeys) { - lines.push(`import { ${keysName} } from '../query-keys';`); - lines.push(`import { ${mutationKeysName} } from '../mutation-keys';`); - } - - lines.push(`import type {`); - lines.push(` ${selectTypeName},`); - lines.push(` ${relationTypeName},`); - lines.push(` ${createInputTypeName},`); - lines.push(`} from '../../orm/input-types';`); - lines.push(`import type { InferSelectResult, StrictSelect } from '../../orm/select-types';`); - lines.push(''); - - // Re-export types - lines.push(`export type { ${selectTypeName}, ${relationTypeName}, ${createInputTypeName} } from '../../orm/input-types';`); - lines.push(''); - - lines.push(`const defaultSelect = { ${defaultFieldName}: true } as const;`); - lines.push(''); - - // Hook - lines.push(`/**`); - lines.push(` * Mutation hook for creating a ${typeName}`); - lines.push(` *`); - lines.push(` * @example`); - lines.push(` * \`\`\`tsx`); - lines.push(` * const { mutate, isPending } = ${hookName}({`); - lines.push(` * selection: { fields: { id: true, name: true } },`); - lines.push(` * });`); - lines.push(` *`); - lines.push(` * mutate({ name: 'New item' });`); - lines.push(` * \`\`\``); - lines.push(` */`); - const createResultType = (s: string) => `{ ${mutationName}: { ${singularName}: InferSelectResult<${relationTypeName}, ${s}> } }`; - const createVarType = `${createInputTypeName}['${singularName}']`; - const createOptionsType = (s: string) => `Omit, 'mutationFn'>`; - const selectionWithFieldsType = (s: string) => - `({ fields: ${s} } & StrictSelect<${s}, ${selectTypeName}>)`; - const selectionWithoutFieldsType = () => `({ fields?: undefined })`; - lines.push(`export function ${hookName}(`); - lines.push(` params: { selection: ${selectionWithFieldsType('S')} } & ${createOptionsType('S')}`); - lines.push(`): UseMutationResult<${createResultType('S')}, Error, ${createVarType}>;`); - lines.push(`export function ${hookName}(`); - lines.push(` params?: { selection?: ${selectionWithoutFieldsType()} } & ${createOptionsType('typeof defaultSelect')}`); - lines.push(`): UseMutationResult<${createResultType('typeof defaultSelect')}, Error, ${createVarType}>;`); - lines.push(`export function ${hookName}(`); - lines.push(` params?: { selection?: SelectionConfig<${selectTypeName}> } & Omit, 'mutationFn'>`); - lines.push(`) {`); - lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); - lines.push(` const { selection: _selection, ...mutationOptions } = params ?? {};`); - lines.push(` void _selection;`); - lines.push(` const queryClient = useQueryClient();`); - lines.push(` return useMutation({`); + statements.push(createImportDeclaration('@tanstack/react-query', ['useMutation', 'useQueryClient'])); + statements.push(createImportDeclaration('@tanstack/react-query', ['UseMutationOptions', 'UseMutationResult'], true)); + statements.push(createImportDeclaration('../client', ['getClient'])); + statements.push(createImportDeclaration('../selection', ['buildSelectionArgs'])); + statements.push(createImportDeclaration('../selection', ['SelectionConfig'], true)); if (useCentralizedKeys) { - lines.push(` mutationKey: ${mutationKeysName}.create(),`); + statements.push(createImportDeclaration('../query-keys', [keysName])); + statements.push(createImportDeclaration('../mutation-keys', [mutationKeysName])); } - lines.push(` mutationFn: (data: ${createInputTypeName}['${singularName}']) => getClient().${singularName}.create({ data, select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - - const listKey = useCentralizedKeys - ? `${keysName}.lists()` - : `['${typeName.toLowerCase()}', 'list']`; - lines.push(` onSuccess: () => {`); - lines.push(` queryClient.invalidateQueries({ queryKey: ${listKey} });`); - lines.push(` },`); - lines.push(` ...mutationOptions,`); - lines.push(` });`); - lines.push(`}`); - - const content = getGeneratedFileHeader(`Create mutation hook for ${typeName}`) + '\n\n' + lines.join('\n') + '\n'; + statements.push(createImportDeclaration('../../orm/input-types', [selectTypeName, relationTypeName, createInputTypeName], true)); + statements.push(createImportDeclaration('../../orm/select-types', ['InferSelectResult', 'StrictSelect'], true)); + + // Re-exports + statements.push(createTypeReExport([selectTypeName, relationTypeName, createInputTypeName], '../../orm/input-types')); + + // Default select + statements.push(constDecl('defaultSelect', asConst(t.objectExpression([objectProp(defaultFieldName, t.booleanLiteral(true))])))); + + // Variable type: CreateTypeName['singularName'] + const createVarType = t.tsIndexedAccessType( + typeRef(createInputTypeName), + t.tsLiteralType(t.stringLiteral(singularName)) + ); + + 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()), createVarType) + ]); + const o1 = exportDeclareFunction( + hookName, + createSTypeParam(selectTypeName), + [createFunctionParam('params', o1ParamType)], + useMutationResultType(resultType(sRef()), createVarType) + ); + addJSDocComment(o1, [ + `Mutation hook for creating a ${typeName}`, + '', + '@example', + '```tsx', + `const { mutate, isPending } = ${hookName}({`, + ' selection: { fields: { id: true, name: true } },', + '});', + '', + "mutate({ name: 'New item' });", + '```' + ]); + statements.push(o1); + + // Overload 2: without fields + const o2SelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(buildNoFieldsType())); + o2SelProp.optional = true; + const o2ParamType = t.tsIntersectionType([ + t.tsTypeLiteral([o2SelProp]), + useMutationOptionsType(resultType(typeofRef('defaultSelect')), createVarType) + ]); + statements.push( + exportDeclareFunction( + hookName, + null, + [createFunctionParam('params', o2ParamType, true)], + useMutationResultType(resultType(typeofRef('defaultSelect')), createVarType) + ) + ); + + // Implementation + const implSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName)))); + implSelProp.optional = true; + 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', buildSelectFallback(selectTypeName)) + ])) + ); + + // 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)])] + ) + ) + ]) + ); + + body.push( + returnUseMutation( + mutationFnExpr, + [ + objectProp('onSuccess', onSuccessFn), + spreadObj(t.identifier('mutationOptions')) + ], + mutationKeyExpr + ) + ); + + statements.push(exportFunction(hookName, null, [createFunctionParam('params', implParamType, true)], body)); return { fileName: getCreateMutationFileName(table), - content + content: generateHookFileCode(`Create mutation hook for ${typeName}`, statements) }; } @@ -156,17 +278,9 @@ export function generateUpdateMutationHook( useCentralizedKeys = true } = options; - if (!reactQueryEnabled) { - return null; - } - - if (table.query?.update === null) { - return null; - } - - if (!hasValidPrimaryKey(table)) { - return null; - } + if (!reactQueryEnabled) return null; + if (table.query?.update === null) return null; + if (!hasValidPrimaryKey(table)) return null; const { typeName, singularName } = getTableNames(table); const hookName = getUpdateMutationHookName(table); @@ -180,95 +294,162 @@ export function generateUpdateMutationHook( const pkFields = getPrimaryKeyInfo(table); const pkField = pkFields[0]; - const lines: string[] = []; - - // Imports - lines.push(`import { useMutation, useQueryClient } from '@tanstack/react-query';`); - lines.push(`import type { UseMutationOptions, UseMutationResult } from '@tanstack/react-query';`); - lines.push(`import { getClient } from '../client';`); - lines.push(`import { buildSelectionArgs } from '../selection';`); - lines.push(`import type { SelectionConfig } from '../selection';`); + const pkTsType = pkField.tsType === 'string' ? t.tsStringKeyword() : t.tsNumberKeyword(); - if (useCentralizedKeys) { - lines.push(`import { ${keysName} } from '../query-keys';`); - lines.push(`import { ${mutationKeysName} } from '../mutation-keys';`); - } + const statements: t.Statement[] = []; - lines.push(`import type {`); - lines.push(` ${selectTypeName},`); - lines.push(` ${relationTypeName},`); - lines.push(` ${patchTypeName},`); - lines.push(`} from '../../orm/input-types';`); - lines.push(`import type { InferSelectResult, StrictSelect } from '../../orm/select-types';`); - lines.push(''); - - // Re-export types - lines.push(`export type { ${selectTypeName}, ${relationTypeName}, ${patchTypeName} } from '../../orm/input-types';`); - lines.push(''); - - lines.push(`const defaultSelect = { ${pkField.name}: true } as const;`); - lines.push(''); - - // Hook - lines.push(`/**`); - lines.push(` * Mutation hook for updating a ${typeName}`); - lines.push(` *`); - lines.push(` * @example`); - lines.push(` * \`\`\`tsx`); - lines.push(` * const { mutate, isPending } = ${hookName}({`); - lines.push(` * selection: { fields: { id: true, name: true } },`); - lines.push(` * });`); - lines.push(` *`); - lines.push(` * mutate({ ${pkField.name}: 'value-here', patch: { name: 'Updated' } });`); - lines.push(` * \`\`\``); - lines.push(` */`); - const updateResultType = (s: string) => `{ ${mutationName}: { ${singularName}: InferSelectResult<${relationTypeName}, ${s}> } }`; - const updateVarType = `{ ${pkField.name}: ${pkField.tsType}; patch: ${patchTypeName} }`; - const updateOptionsType = (s: string) => `Omit, 'mutationFn'>`; - const selectionWithFieldsType = (s: string) => - `({ fields: ${s} } & StrictSelect<${s}, ${selectTypeName}>)`; - const selectionWithoutFieldsType = () => `({ fields?: undefined })`; - lines.push(`export function ${hookName}(`); - lines.push(` params: { selection: ${selectionWithFieldsType('S')} } & ${updateOptionsType('S')}`); - lines.push(`): UseMutationResult<${updateResultType('S')}, Error, ${updateVarType}>;`); - lines.push(`export function ${hookName}(`); - lines.push(` params?: { selection?: ${selectionWithoutFieldsType()} } & ${updateOptionsType('typeof defaultSelect')}`); - lines.push(`): UseMutationResult<${updateResultType('typeof defaultSelect')}, Error, ${updateVarType}>;`); - lines.push(`export function ${hookName}(`); - lines.push(` params?: { selection?: SelectionConfig<${selectTypeName}> } & Omit, 'mutationFn'>`); - lines.push(`) {`); - lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); - lines.push(` const { selection: _selection, ...mutationOptions } = params ?? {};`); - lines.push(` void _selection;`); - lines.push(` const queryClient = useQueryClient();`); - lines.push(` return useMutation({`); + // Imports + statements.push(createImportDeclaration('@tanstack/react-query', ['useMutation', 'useQueryClient'])); + statements.push(createImportDeclaration('@tanstack/react-query', ['UseMutationOptions', 'UseMutationResult'], true)); + statements.push(createImportDeclaration('../client', ['getClient'])); + statements.push(createImportDeclaration('../selection', ['buildSelectionArgs'])); + statements.push(createImportDeclaration('../selection', ['SelectionConfig'], true)); if (useCentralizedKeys) { - lines.push(` mutationKey: ${mutationKeysName}.all,`); + statements.push(createImportDeclaration('../query-keys', [keysName])); + statements.push(createImportDeclaration('../mutation-keys', [mutationKeysName])); } - lines.push(` mutationFn: ({ ${pkField.name}, patch }: { ${pkField.name}: ${pkField.tsType}; patch: ${patchTypeName} }) => getClient().${singularName}.update({ where: { ${pkField.name} }, data: patch, select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - - const detailKey = useCentralizedKeys - ? `${keysName}.detail(variables.${pkField.name})` - : `['${typeName.toLowerCase()}', 'detail', variables.${pkField.name}]`; - const listKey = useCentralizedKeys - ? `${keysName}.lists()` - : `['${typeName.toLowerCase()}', 'list']`; - - lines.push(` onSuccess: (_, variables) => {`); - lines.push(` queryClient.invalidateQueries({ queryKey: ${detailKey} });`); - lines.push(` queryClient.invalidateQueries({ queryKey: ${listKey} });`); - lines.push(` },`); - lines.push(` ...mutationOptions,`); - lines.push(` });`); - lines.push(`}`); - - const content = getGeneratedFileHeader(`Update mutation hook for ${typeName}`) + '\n\n' + lines.join('\n') + '\n'; + statements.push(createImportDeclaration('../../orm/input-types', [selectTypeName, relationTypeName, patchTypeName], true)); + statements.push(createImportDeclaration('../../orm/select-types', ['InferSelectResult', 'StrictSelect'], true)); + + // Re-exports + statements.push(createTypeReExport([selectTypeName, relationTypeName, patchTypeName], '../../orm/input-types')); + + // Default select + statements.push(constDecl('defaultSelect', asConst(t.objectExpression([objectProp(pkField.name, t.booleanLiteral(true))])))); + + // Variable type: { pkField: type; patch: PatchType } + const updateVarType = t.tsTypeLiteral([ + t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkTsType)), + t.tsPropertySignature(t.identifier('patch'), t.tsTypeAnnotation(typeRef(patchTypeName))) + ]); + + 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); + + // Overload 2: without fields + const o2SelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(buildNoFieldsType())); + o2SelProp.optional = true; + const o2ParamType = t.tsIntersectionType([ + t.tsTypeLiteral([o2SelProp]), + useMutationOptionsType(resultType(typeofRef('defaultSelect')), updateVarType) + ]); + statements.push( + exportDeclareFunction( + hookName, + null, + [createFunctionParam('params', o2ParamType, true)], + useMutationResultType(resultType(typeofRef('defaultSelect')), updateVarType) + ) + ); + + // Implementation + const implSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName)))); + implSelProp.optional = true; + const implParamType = t.tsIntersectionType([ + t.tsTypeLiteral([implSelProp]), + omitType(typeRef('UseMutationOptions', [t.tsAnyKeyword(), typeRef('Error'), updateVarType]), ['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 + ? 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', buildSelectFallback(selectTypeName)) + ])) + ); + + // onSuccess: invalidate detail and lists + const detailKeyExpr = useCentralizedKeys + ? callExpr(t.memberExpression(t.identifier(keysName), t.identifier('detail')), [ + t.memberExpression(t.identifier('variables'), t.identifier(pkField.name)) + ]) + : t.arrayExpression([t.stringLiteral(typeName.toLowerCase()), t.stringLiteral('detail'), 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 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.objectExpression([objectProp('queryKey', detailKeyExpr)])] + ) + ), + t.expressionStatement( + callExpr( + t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), + [t.objectExpression([objectProp('queryKey', listKeyExpr)])] + ) + ) + ]) + ); + + body.push( + returnUseMutation( + mutationFnExpr, + [ + objectProp('onSuccess', onSuccessFn), + spreadObj(t.identifier('mutationOptions')) + ], + mutationKeyExpr + ) + ); + + statements.push(exportFunction(hookName, null, [createFunctionParam('params', implParamType, true)], body)); return { fileName: getUpdateMutationFileName(table), - content + content: generateHookFileCode(`Update mutation hook for ${typeName}`, statements) }; } @@ -281,17 +462,9 @@ export function generateDeleteMutationHook( useCentralizedKeys = true } = options; - if (!reactQueryEnabled) { - return null; - } - - if (table.query?.delete === null) { - return null; - } - - if (!hasValidPrimaryKey(table)) { - return null; - } + if (!reactQueryEnabled) return null; + if (table.query?.delete === null) return null; + if (!hasValidPrimaryKey(table)) return null; const { typeName, singularName } = getTableNames(table); const hookName = getDeleteMutationHookName(table); @@ -304,94 +477,155 @@ export function generateDeleteMutationHook( const pkFields = getPrimaryKeyInfo(table); const pkField = pkFields[0]; - const lines: string[] = []; + const pkTsType = pkField.tsType === 'string' ? t.tsStringKeyword() : t.tsNumberKeyword(); - // Imports - lines.push(`import { useMutation, useQueryClient } from '@tanstack/react-query';`); - lines.push(`import type { UseMutationOptions, UseMutationResult } from '@tanstack/react-query';`); - lines.push(`import { getClient } from '../client';`); - lines.push(`import { buildSelectionArgs } from '../selection';`); - lines.push(`import type { SelectionConfig } from '../selection';`); + const statements: t.Statement[] = []; - if (useCentralizedKeys) { - lines.push(`import { ${keysName} } from '../query-keys';`); - lines.push(`import { ${mutationKeysName} } from '../mutation-keys';`); - } - - lines.push(`import type {`); - lines.push(` ${selectTypeName},`); - lines.push(` ${relationTypeName},`); - lines.push(`} from '../../orm/input-types';`); - lines.push(`import type { InferSelectResult, StrictSelect } from '../../orm/select-types';`); - lines.push(''); - - // Re-export types - lines.push(`export type { ${selectTypeName}, ${relationTypeName} } from '../../orm/input-types';`); - lines.push(''); - - lines.push(`const defaultSelect = { ${pkField.name}: true } as const;`); - lines.push(''); - - // Hook - lines.push(`/**`); - lines.push(` * Mutation hook for deleting a ${typeName}`); - lines.push(` *`); - lines.push(` * @example`); - lines.push(` * \`\`\`tsx`); - lines.push(` * const { mutate, isPending } = ${hookName}({`); - lines.push(` * selection: { fields: { id: true } },`); - lines.push(` * });`); - lines.push(` *`); - lines.push(` * mutate({ ${pkField.name}: ${pkField.tsType === 'string' ? "'value-to-delete'" : '123'} });`); - lines.push(` * \`\`\``); - lines.push(` */`); - const deleteResultType = (s: string) => `{ ${mutationName}: { ${singularName}: InferSelectResult<${relationTypeName}, ${s}> } }`; - const deleteVarType = `{ ${pkField.name}: ${pkField.tsType} }`; - const deleteOptionsType = (s: string) => `Omit, 'mutationFn'>`; - const selectionWithFieldsType = (s: string) => - `({ fields: ${s} } & StrictSelect<${s}, ${selectTypeName}>)`; - const selectionWithoutFieldsType = () => `({ fields?: undefined })`; - lines.push(`export function ${hookName}(`); - lines.push(` params: { selection: ${selectionWithFieldsType('S')} } & ${deleteOptionsType('S')}`); - lines.push(`): UseMutationResult<${deleteResultType('S')}, Error, ${deleteVarType}>;`); - lines.push(`export function ${hookName}(`); - lines.push(` params?: { selection?: ${selectionWithoutFieldsType()} } & ${deleteOptionsType('typeof defaultSelect')}`); - lines.push(`): UseMutationResult<${deleteResultType('typeof defaultSelect')}, Error, ${deleteVarType}>;`); - lines.push(`export function ${hookName}(`); - lines.push(` params?: { selection?: SelectionConfig<${selectTypeName}> } & Omit, 'mutationFn'>`); - lines.push(`) {`); - lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params?.selection);`); - lines.push(` const { selection: _selection, ...mutationOptions } = params ?? {};`); - lines.push(` void _selection;`); - lines.push(` const queryClient = useQueryClient();`); - lines.push(` return useMutation({`); + // Imports + statements.push(createImportDeclaration('@tanstack/react-query', ['useMutation', 'useQueryClient'])); + statements.push(createImportDeclaration('@tanstack/react-query', ['UseMutationOptions', 'UseMutationResult'], true)); + statements.push(createImportDeclaration('../client', ['getClient'])); + statements.push(createImportDeclaration('../selection', ['buildSelectionArgs'])); + statements.push(createImportDeclaration('../selection', ['SelectionConfig'], true)); if (useCentralizedKeys) { - lines.push(` mutationKey: ${mutationKeysName}.all,`); + statements.push(createImportDeclaration('../query-keys', [keysName])); + statements.push(createImportDeclaration('../mutation-keys', [mutationKeysName])); } - lines.push(` mutationFn: ({ ${pkField.name} }: { ${pkField.name}: ${pkField.tsType} }) => getClient().${singularName}.delete({ where: { ${pkField.name} }, select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - - const detailKey = useCentralizedKeys - ? `${keysName}.detail(variables.${pkField.name})` - : `['${typeName.toLowerCase()}', 'detail', variables.${pkField.name}]`; - const listKey = useCentralizedKeys - ? `${keysName}.lists()` - : `['${typeName.toLowerCase()}', 'list']`; - - lines.push(` onSuccess: (_, variables) => {`); - lines.push(` queryClient.removeQueries({ queryKey: ${detailKey} });`); - lines.push(` queryClient.invalidateQueries({ queryKey: ${listKey} });`); - lines.push(` },`); - lines.push(` ...mutationOptions,`); - lines.push(` });`); - lines.push(`}`); - - const content = getGeneratedFileHeader(`Delete mutation hook for ${typeName}`) + '\n\n' + lines.join('\n') + '\n'; + statements.push(createImportDeclaration('../../orm/input-types', [selectTypeName, relationTypeName], true)); + statements.push(createImportDeclaration('../../orm/select-types', ['InferSelectResult', 'StrictSelect'], true)); + + // Re-exports + statements.push(createTypeReExport([selectTypeName, relationTypeName], '../../orm/input-types')); + + // Default select + statements.push(constDecl('defaultSelect', asConst(t.objectExpression([objectProp(pkField.name, t.booleanLiteral(true))])))); + + // Variable type: { pkField: type } + const deleteVarType = t.tsTypeLiteral([ + t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkTsType)) + ]); + + 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}`, + '', + '@example', + '```tsx', + `const { mutate, isPending } = ${hookName}({`, + ' selection: { fields: { id: true } },', + '});', + '', + `mutate({ ${pkField.name}: ${pkField.tsType === 'string' ? "'value-to-delete'" : '123'} });`, + '```' + ]); + statements.push(o1); + + // Overload 2: without fields + const o2SelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(buildNoFieldsType())); + o2SelProp.optional = true; + const o2ParamType = t.tsIntersectionType([ + t.tsTypeLiteral([o2SelProp]), + useMutationOptionsType(resultType(typeofRef('defaultSelect')), deleteVarType) + ]); + statements.push( + exportDeclareFunction( + hookName, + null, + [createFunctionParam('params', o2ParamType, true)], + useMutationResultType(resultType(typeofRef('defaultSelect')), deleteVarType) + ) + ); + + // Implementation + const implSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName)))); + implSelProp.optional = true; + const implParamType = t.tsIntersectionType([ + t.tsTypeLiteral([implSelProp]), + omitType(typeRef('UseMutationOptions', [t.tsAnyKeyword(), typeRef('Error'), deleteVarType]), ['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 + ? 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', buildSelectFallback(selectTypeName)) + ])) + ); + + // onSuccess: remove detail, invalidate lists + const detailKeyExpr = useCentralizedKeys + ? callExpr(t.memberExpression(t.identifier(keysName), t.identifier('detail')), [ + t.memberExpression(t.identifier('variables'), t.identifier(pkField.name)) + ]) + : t.arrayExpression([t.stringLiteral(typeName.toLowerCase()), t.stringLiteral('detail'), 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 onSuccessFn = t.arrowFunctionExpression( + [t.identifier('_'), t.identifier('variables')], + t.blockStatement([ + t.expressionStatement( + callExpr( + t.memberExpression(t.identifier('queryClient'), t.identifier('removeQueries')), + [t.objectExpression([objectProp('queryKey', detailKeyExpr)])] + ) + ), + t.expressionStatement( + callExpr( + t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), + [t.objectExpression([objectProp('queryKey', listKeyExpr)])] + ) + ) + ]) + ); + + body.push( + returnUseMutation( + mutationFnExpr, + [ + objectProp('onSuccess', onSuccessFn), + spreadObj(t.identifier('mutationOptions')) + ], + mutationKeyExpr + ) + ); + + statements.push(exportFunction(hookName, null, [createFunctionParam('params', implParamType, true)], body)); return { fileName: getDeleteMutationFileName(table), - content + content: generateHookFileCode(`Delete mutation hook for ${typeName}`, statements) }; } diff --git a/graphql/codegen/src/core/codegen/queries.ts b/graphql/codegen/src/core/codegen/queries.ts index 66146e42f..38e4e5395 100644 --- a/graphql/codegen/src/core/codegen/queries.ts +++ b/graphql/codegen/src/core/codegen/queries.ts @@ -1,17 +1,64 @@ /** - * Query hook generators - delegates to ORM model methods + * Query hook generators - delegates to ORM model methods (Babel AST-based) * * Output structure: * queries/ * useCarsQuery.ts - List query hook -> ORM findMany * useCarQuery.ts - Single item query hook -> ORM findOne */ +import * as t from '@babel/types'; + import type { CleanTable } from '../../types/schema'; +import { asConst } from './babel-ast'; +import { + addJSDocComment, + buildFindManyCallExpr, + buildFindOneCallExpr, + buildListSelectionArgsCall, + buildSelectionArgsCall, + buildSelectFallbackExpr, + callExpr, + connectionResultType, + constDecl, + createFunctionParam, + createImportDeclaration, + createSAndTDataTypeParams, + createSTypeParam, + createTDataTypeParam, + createTypeReExport, + destructureParamsWithSelection, + destructureParamsWithSelectionAndScope, + exportAsyncDeclareFunction, + exportAsyncFunction, + exportDeclareFunction, + exportFunction, + generateHookFileCode, + inferSelectResultType, + listQueryResultType, + listSelectionConfigType, + objectProp, + omitType, + returnUseQuery, + scopeTypeLiteral, + selectionConfigType, + singleQueryResultType, + spreadObj, + sRef, + typeofRef, + typeRef, + typeLiteralWithProps, + useQueryOptionsType, + useQueryOptionsImplType, + voidStatement, + withFieldsListSelectionType, + withFieldsSelectionType, + withoutFieldsListSelectionType, + withoutFieldsSelectionType +} from './hooks-ast'; import { getAllRowsQueryName, getDefaultSelectFieldName, getFilterTypeName, - getGeneratedFileHeader, getListQueryFileName, getListQueryHookName, getOrderByTypeName, @@ -54,229 +101,346 @@ export function generateListQueryHook( const scopeTypeName = `${typeName}Scope`; const selectTypeName = `${typeName}Select`; const relationTypeName = `${typeName}WithRelations`; - const defaultFieldName = getDefaultSelectFieldName(table); - const listResultType = (s: string) => `{ ${queryName}: ConnectionResult> }`; - const selectionType = (s: string) => `ListSelectionConfig<${s}, ${filterTypeName}, ${orderByTypeName}>`; - const selectionWithFieldsType = (s: string) => - `({ fields: ${s} } & Omit<${selectionType(s)}, 'fields'> & StrictSelect<${s}, ${selectTypeName}>)`; - const selectionWithoutFieldsType = () => - `(Omit<${selectionType(selectTypeName)}, 'fields'> & { fields?: undefined })`; - const lines: string[] = []; + const listResultTypeAST = (sel: t.TSType) => listQueryResultType(queryName, relationTypeName, sel); + + const statements: t.Statement[] = []; // Imports if (reactQueryEnabled) { - lines.push(`import { useQuery } from '@tanstack/react-query';`); - lines.push(`import type { UseQueryOptions, UseQueryResult, QueryClient } from '@tanstack/react-query';`); + statements.push(createImportDeclaration('@tanstack/react-query', ['useQuery'])); + statements.push(createImportDeclaration('@tanstack/react-query', ['UseQueryOptions', 'UseQueryResult', 'QueryClient'], true)); } - lines.push(`import { getClient } from '../client';`); - lines.push(`import { buildListSelectionArgs } from '../selection';`); - lines.push(`import type { ListSelectionConfig } from '../selection';`); + statements.push(createImportDeclaration('../client', ['getClient'])); + statements.push(createImportDeclaration('../selection', ['buildListSelectionArgs'])); + statements.push(createImportDeclaration('../selection', ['ListSelectionConfig'], true)); if (useCentralizedKeys) { - lines.push(`import { ${keysName} } from '../query-keys';`); + statements.push(createImportDeclaration('../query-keys', [keysName])); if (hasRelationships) { - lines.push(`import type { ${scopeTypeName} } from '../query-keys';`); + statements.push(createImportDeclaration('../query-keys', [scopeTypeName], true)); } } - lines.push(`import type {`); - lines.push(` ${selectTypeName},`); - lines.push(` ${relationTypeName},`); - lines.push(` ${filterTypeName},`); - lines.push(` ${orderByTypeName},`); - lines.push(`} from '../../orm/input-types';`); - lines.push(`import type {`); - lines.push(` FindManyArgs,`); - lines.push(` InferSelectResult,`); - lines.push(` ConnectionResult,`); - lines.push(` StrictSelect,`); - lines.push(`} from '../../orm/select-types';`); - lines.push(''); - - // Re-export types for backwards compat - lines.push(`export type { ${selectTypeName}, ${relationTypeName}, ${filterTypeName}, ${orderByTypeName} } from '../../orm/input-types';`); - lines.push(''); - - lines.push(`const defaultSelect = { ${defaultFieldName}: true } as const;`); - lines.push(''); + statements.push(createImportDeclaration('../../orm/input-types', [selectTypeName, relationTypeName, filterTypeName, orderByTypeName], true)); + statements.push(createImportDeclaration('../../orm/select-types', ['FindManyArgs', 'InferSelectResult', 'ConnectionResult', 'StrictSelect'], true)); + + // Re-exports + statements.push(createTypeReExport([selectTypeName, relationTypeName, filterTypeName, orderByTypeName], '../../orm/input-types')); + + // Default select + statements.push(constDecl('defaultSelect', asConst(t.objectExpression([objectProp(defaultFieldName, t.booleanLiteral(true))])))); // Query key if (useCentralizedKeys) { - lines.push(`/** Query key factory - re-exported from query-keys.ts */`); - lines.push(`export const ${queryName}QueryKey = ${keysName}.list;`); + 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(keyDecl); } else { - lines.push(`export const ${queryName}QueryKey = (variables?: FindManyArgs) => ['${typeName.toLowerCase()}', 'list', variables] as const;`); + const keyFn = t.arrowFunctionExpression( + [createFunctionParam('variables', typeRef('FindManyArgs', [t.tsUnknownKeyword(), typeRef(filterTypeName), typeRef(orderByTypeName)]), true)], + asConst(t.arrayExpression([t.stringLiteral(typeName.toLowerCase()), t.stringLiteral('list'), t.identifier('variables')])) + ); + statements.push(t.exportNamedDeclaration( + t.variableDeclaration('const', [t.variableDeclarator(t.identifier(`${queryName}QueryKey`), keyFn)]) + )); } - lines.push(''); + + // 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]); + }; + + // Helper for findMany queryFn + const buildFindManyFn = () => t.arrowFunctionExpression( + [], + buildFindManyCallExpr(singularName, 'args', selectTypeName) + ); + + // 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) { + return t.tsIntersectionType([base, scopeTypeLiteral(scopeTypeName)]); + } + return base; + }; // Hook if (reactQueryEnabled) { const docLines = [ - `/**`, - ` * Query hook for fetching ${typeName} list`, - ` *`, - ` * @example`, - ` * \`\`\`tsx`, - ` * const { data, isLoading } = ${hookName}({`, - ` * selection: {`, - ` * fields: { id: true, name: true },`, - ` * where: { name: { equalTo: "example" } },`, - ` * orderBy: ['CREATED_AT_DESC'],`, - ` * first: 10,`, - ` * },`, - ` * });`, - ` * \`\`\`` + `Query hook for fetching ${typeName} list`, + '', + '@example', + '```tsx', + `const { data, isLoading } = ${hookName}({`, + ' selection: {', + ' fields: { id: true, name: true },', + ' where: { name: { equalTo: "example" } },', + " orderBy: ['CREATED_AT_DESC'],", + ' first: 10,', + ' },', + '});', + '```' ]; if (hasRelationships && useCentralizedKeys) { - docLines.push(` *`); - docLines.push(` * @example With scope for hierarchical cache invalidation`); - docLines.push(` * \`\`\`tsx`); - docLines.push(` * const { data } = ${hookName}({`); - docLines.push(` * selection: { first: 10 },`); - docLines.push(` * scope: { parentId: 'parent-id' },`); - docLines.push(` * });`); - docLines.push(` * \`\`\``); + docLines.push(''); + docLines.push('@example With scope for hierarchical cache invalidation'); + docLines.push('```tsx'); + docLines.push(`const { data } = ${hookName}({`); + docLines.push(' selection: { first: 10 },'); + docLines.push(" scope: { parentId: 'parent-id' },"); + docLines.push('});'); + docLines.push('```'); } - docLines.push(` */`); - lines.push(...docLines); - - const optionsType = (queryData: string, data: string) => - hasRelationships && useCentralizedKeys - ? `Omit, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }` - : `Omit, 'queryKey' | 'queryFn'>`; - const implOptionsType = hasRelationships && useCentralizedKeys - ? `Omit, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }` - : `Omit, 'queryKey' | 'queryFn'>`; - - // Overload 1: with selection.fields (autocompletion) - lines.push(`export function ${hookName}(`); - lines.push(` params: { selection: ${selectionWithFieldsType('S')} } & ${optionsType(listResultType('S'), 'TData')}`); - lines.push(`): UseQueryResult;`); - - // Overload 2: no fields (default select) - lines.push(`export function ${hookName}(`); - lines.push(` params?: { selection?: ${selectionWithoutFieldsType()} } & ${optionsType(listResultType('typeof defaultSelect'), 'TData')}`); - lines.push(`): UseQueryResult;`); + + // 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); + + // Overload 2: without fields + const o2SelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(withoutFieldsListSelectionType(selectTypeName, filterTypeName, orderByTypeName)) + ); + o2SelProp.optional = true; + const o2ParamType = t.tsIntersectionType([ + t.tsTypeLiteral([o2SelProp]), + buildOptionsType(listResultTypeAST(typeofRef('defaultSelect')), typeRef('TData')) + ]); + statements.push( + exportDeclareFunction( + hookName, + createTDataTypeParam(listResultTypeAST(typeofRef('defaultSelect'))), + [createFunctionParam('params', o2ParamType, true)], + typeRef('UseQueryResult', [typeRef('TData')]) + ) + ); // Implementation - lines.push(`export function ${hookName}(`); - lines.push(` params?: { selection?: ${selectionType(selectTypeName)} } & ${implOptionsType}`); - lines.push(`) {`); - lines.push(` const selection = params?.selection;`); - lines.push(` const args = buildListSelectionArgs<${selectTypeName}, ${filterTypeName}, ${orderByTypeName}>(selection);`); + const implSelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(listSelectionConfigType(typeRef(selectTypeName), filterTypeName, orderByTypeName)) + ); + implSelProp.optional = 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(constDecl('selection', t.optionalMemberExpression(t.identifier('params'), t.identifier('selection'), false, true))); + body.push(buildListSelectionArgsCall(selectTypeName, filterTypeName, orderByTypeName)); if (hasRelationships && useCentralizedKeys) { - lines.push(` const { scope, selection: _selection, ...queryOptions } = params ?? {};`); - lines.push(` void _selection;`); - lines.push(` return useQuery({`); - lines.push(` queryKey: ${keysName}.list(args, scope),`); - lines.push(` queryFn: () => getClient().${singularName}.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - lines.push(` ...queryOptions,`); - lines.push(` });`); - } else if (useCentralizedKeys) { - lines.push(` const { selection: _selection, ...queryOptions } = params ?? {};`); - lines.push(` void _selection;`); - lines.push(` return useQuery({`); - lines.push(` queryKey: ${keysName}.list(args),`); - lines.push(` queryFn: () => getClient().${singularName}.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - lines.push(` ...queryOptions,`); - lines.push(` });`); + body.push(destructureParamsWithSelectionAndScope('queryOptions')); + body.push(voidStatement('_selection')); + body.push(returnUseQuery( + buildListQueryKey(t.identifier('args'), t.identifier('scope')), + buildFindManyFn(), + [spreadObj(t.identifier('queryOptions'))] + )); } else { - lines.push(` const { selection: _selection, ...queryOptions } = params ?? {};`); - lines.push(` void _selection;`); - lines.push(` return useQuery({`); - lines.push(` queryKey: ${queryName}QueryKey(args),`); - lines.push(` queryFn: () => getClient().${singularName}.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - lines.push(` ...queryOptions,`); - lines.push(` });`); + body.push(destructureParamsWithSelection('queryOptions')); + body.push(voidStatement('_selection')); + body.push(returnUseQuery( + buildListQueryKey(t.identifier('args')), + buildFindManyFn(), + [spreadObj(t.identifier('queryOptions'))] + )); } - lines.push(`}`); - lines.push(''); + statements.push(exportFunction(hookName, null, [createFunctionParam('params', implParamType, true)], body)); } - // Fetch function (non-hook) - lines.push(`/**`); - lines.push(` * Fetch ${typeName} list without React hooks`); - lines.push(` *`); - lines.push(` * @example`); - lines.push(` * \`\`\`ts`); - lines.push(` * const data = await fetch${ucFirst(pluralName)}Query({`); - lines.push(` * selection: {`); - lines.push(` * fields: { id: true },`); - lines.push(` * first: 10,`); - lines.push(` * },`); - lines.push(` * });`); - lines.push(` * \`\`\``); - lines.push(` */`); - lines.push(`export async function fetch${ucFirst(pluralName)}Query(`); - lines.push(` params: { selection: ${selectionWithFieldsType('S')} }`); - lines.push(`): Promise<${listResultType('S')}>;`); - lines.push(`export async function fetch${ucFirst(pluralName)}Query(`); - lines.push(` params?: { selection?: ${selectionWithoutFieldsType()} }`); - lines.push(`): Promise<${listResultType('typeof defaultSelect')}>;`); - lines.push(`export async function fetch${ucFirst(pluralName)}Query(`); - lines.push(` params?: { selection?: ${selectionType(selectTypeName)} }`); - lines.push(`) {`); - lines.push(` const args = buildListSelectionArgs<${selectTypeName}, ${filterTypeName}, ${orderByTypeName}>(params?.selection);`); - lines.push(` return getClient().${singularName}.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap();`); - lines.push(`}`); - lines.push(''); + // 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); + + // Overload 2: without fields + const f2SelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(withoutFieldsListSelectionType(selectTypeName, filterTypeName, orderByTypeName)) + ); + f2SelProp.optional = true; + statements.push( + exportAsyncDeclareFunction( + fetchFnName, + null, + [createFunctionParam('params', t.tsTypeLiteral([f2SelProp]), true)], + typeRef('Promise', [listResultTypeAST(typeofRef('defaultSelect'))]) + ) + ); + + // Implementation + const fImplSelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(listSelectionConfigType(typeRef(selectTypeName), filterTypeName, orderByTypeName)) + ); + fImplSelProp.optional = true; + const fBody: t.Statement[] = []; + fBody.push(buildListSelectionArgsCall(selectTypeName, filterTypeName, orderByTypeName)); + fBody.push(t.returnStatement(buildFindManyCallExpr(singularName, 'args', selectTypeName))); + statements.push(exportAsyncFunction(fetchFnName, null, [createFunctionParam('params', t.tsTypeLiteral([fImplSelProp]), true)], fBody)); + } // Prefetch function if (reactQueryEnabled) { - lines.push(`/**`); - lines.push(` * Prefetch ${typeName} list for SSR or cache warming`); - lines.push(` *`); - lines.push(` * @example`); - lines.push(` * \`\`\`ts`); - lines.push(` * await prefetch${ucFirst(pluralName)}Query(queryClient, { selection: { first: 10 } });`); - lines.push(` * \`\`\``); - lines.push(` */`); - lines.push(`export async function prefetch${ucFirst(pluralName)}Query(`); - lines.push(` queryClient: QueryClient,`); - lines.push(` params: { selection: ${selectionWithFieldsType('S')} }${hasRelationships && useCentralizedKeys ? ` & { scope?: ${scopeTypeName} }` : ''}`); - lines.push(`): Promise;`); - lines.push(`export async function prefetch${ucFirst(pluralName)}Query(`); - lines.push(` queryClient: QueryClient,`); - lines.push(` params?: { selection?: ${selectionWithoutFieldsType()} }${hasRelationships && useCentralizedKeys ? ` & { scope?: ${scopeTypeName} }` : ''}`); - lines.push(`): Promise;`); - lines.push(`export async function prefetch${ucFirst(pluralName)}Query(`); - lines.push(` queryClient: QueryClient,`); - lines.push(` params?: { selection?: ${selectionType(selectTypeName)} }${hasRelationships && useCentralizedKeys ? ` & { scope?: ${scopeTypeName} }` : ''}`); - lines.push(`): Promise {`); - lines.push(` const args = buildListSelectionArgs<${selectTypeName}, ${filterTypeName}, ${orderByTypeName}>(params?.selection);`); - - if (hasRelationships && useCentralizedKeys) { - lines.push(` await queryClient.prefetchQuery({`); - lines.push(` queryKey: ${keysName}.list(args, params?.scope),`); - lines.push(` queryFn: () => getClient().${singularName}.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - lines.push(` });`); - } else if (useCentralizedKeys) { - lines.push(` await queryClient.prefetchQuery({`); - lines.push(` queryKey: ${keysName}.list(args),`); - lines.push(` queryFn: () => getClient().${singularName}.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - lines.push(` });`); - } else { - lines.push(` await queryClient.prefetchQuery({`); - lines.push(` queryKey: ${queryName}QueryKey(args),`); - lines.push(` queryFn: () => getClient().${singularName}.findMany({ ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - lines.push(` });`); - } + 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 ${prefetchFnName}(queryClient, { selection: { first: 10 } });`, + '```' + ]); + statements.push(p1Decl); + + // Overload 2: without fields + const p2SelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(withoutFieldsListSelectionType(selectTypeName, filterTypeName, orderByTypeName)) + ); + p2SelProp.optional = true; + const p2ParamType = hasRelationships && useCentralizedKeys + ? t.tsIntersectionType([t.tsTypeLiteral([p2SelProp]), scopeTypeLiteral(scopeTypeName)]) + : t.tsTypeLiteral([p2SelProp]); + statements.push( + exportAsyncDeclareFunction( + prefetchFnName, + null, + [createFunctionParam('queryClient', typeRef('QueryClient')), createFunctionParam('params', p2ParamType, true)], + typeRef('Promise', [t.tsVoidKeyword()]) + ) + ); - lines.push(`}`); + // Implementation + const pImplSelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(listSelectionConfigType(typeRef(selectTypeName), filterTypeName, orderByTypeName)) + ); + pImplSelProp.optional = true; + const pImplParamType = hasRelationships && useCentralizedKeys + ? t.tsIntersectionType([t.tsTypeLiteral([pImplSelProp]), scopeTypeLiteral(scopeTypeName)]) + : t.tsTypeLiteral([pImplSelProp]); + + 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, true)], + pBody, + t.tsVoidKeyword() + ) + ); } const headerText = reactQueryEnabled ? `List query hook for ${typeName}` : `List query functions for ${typeName}`; - const content = getGeneratedFileHeader(headerText) + '\n\n' + lines.join('\n') + '\n'; return { fileName: getListQueryFileName(table), - content + content: generateHookFileCode(headerText, statements) }; } @@ -284,9 +448,7 @@ export function generateSingleQueryHook( table: CleanTable, options: QueryGeneratorOptions = {} ): GeneratedQueryFile | null { - if (!hasValidPrimaryKey(table)) { - return null; - } + if (!hasValidPrimaryKey(table)) return null; const { reactQueryEnabled = true, @@ -306,217 +468,382 @@ export function generateSingleQueryHook( const pkFieldName = pkField?.name ?? 'id'; const pkFieldTsType = pkField?.tsType ?? 'string'; const defaultFieldName = getDefaultSelectFieldName(table); - const singleResultType = (s: string) => `{ ${queryName}: InferSelectResult<${relationTypeName}, ${s}> | null }`; - const selectionWithFieldsType = (s: string) => - `({ fields: ${s} } & StrictSelect<${s}, ${selectTypeName}>)`; - const selectionWithoutFieldsType = () => `({ fields?: undefined })`; - const lines: string[] = []; + 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) { - lines.push(`import { useQuery } from '@tanstack/react-query';`); - lines.push(`import type { UseQueryOptions, UseQueryResult, QueryClient } from '@tanstack/react-query';`); + statements.push(createImportDeclaration('@tanstack/react-query', ['useQuery'])); + statements.push(createImportDeclaration('@tanstack/react-query', ['UseQueryOptions', 'UseQueryResult', 'QueryClient'], true)); } - lines.push(`import { getClient } from '../client';`); - lines.push(`import { buildSelectionArgs } from '../selection';`); - lines.push(`import type { SelectionConfig } from '../selection';`); + statements.push(createImportDeclaration('../client', ['getClient'])); + statements.push(createImportDeclaration('../selection', ['buildSelectionArgs'])); + statements.push(createImportDeclaration('../selection', ['SelectionConfig'], true)); if (useCentralizedKeys) { - lines.push(`import { ${keysName} } from '../query-keys';`); + statements.push(createImportDeclaration('../query-keys', [keysName])); if (hasRelationships) { - lines.push(`import type { ${scopeTypeName} } from '../query-keys';`); + statements.push(createImportDeclaration('../query-keys', [scopeTypeName], true)); } } - lines.push(`import type {`); - lines.push(` ${selectTypeName},`); - lines.push(` ${relationTypeName},`); - lines.push(`} from '../../orm/input-types';`); - lines.push(`import type {`); - lines.push(` InferSelectResult,`); - lines.push(` StrictSelect,`); - lines.push(`} from '../../orm/select-types';`); - lines.push(''); + statements.push(createImportDeclaration('../../orm/input-types', [selectTypeName, relationTypeName], true)); + statements.push(createImportDeclaration('../../orm/select-types', ['InferSelectResult', 'StrictSelect'], true)); - // Re-export types - lines.push(`export type { ${selectTypeName}, ${relationTypeName} } from '../../orm/input-types';`); - lines.push(''); + // Re-exports + statements.push(createTypeReExport([selectTypeName, relationTypeName], '../../orm/input-types')); - lines.push(`const defaultSelect = { ${defaultFieldName}: true } as const;`); - lines.push(''); + // Default select + statements.push(constDecl('defaultSelect', asConst(t.objectExpression([objectProp(defaultFieldName, t.booleanLiteral(true))])))); // Query key if (useCentralizedKeys) { - lines.push(`/** Query key factory - re-exported from query-keys.ts */`); - lines.push(`export const ${queryName}QueryKey = ${keysName}.detail;`); + 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(keyDecl); } else { - lines.push(`export const ${queryName}QueryKey = (id: ${pkFieldTsType}) => ['${typeName.toLowerCase()}', 'detail', id] as const;`); + const keyFn = t.arrowFunctionExpression( + [createFunctionParam('id', pkTsType)], + asConst(t.arrayExpression([t.stringLiteral(typeName.toLowerCase()), t.stringLiteral('detail'), t.identifier('id')])) + ); + statements.push(t.exportNamedDeclaration( + t.variableDeclaration('const', [t.variableDeclarator(t.identifier(`${queryName}QueryKey`), keyFn)]) + )); } - lines.push(''); + + // 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]); + }; + + // Helper for findOne queryFn + const buildFindOneFn = () => t.arrowFunctionExpression( + [], + buildFindOneCallExpr(singularName, pkFieldName, 'args', selectTypeName) + ); + + // 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'] + ); + 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}({`, - ` * ${pkFieldName}: 'some-id',`, - ` * selection: { fields: { id: true, name: true } },`, - ` * });`, - ` * \`\`\`` + `Query hook for fetching a single ${typeName}`, + '', + '@example', + '```tsx', + `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(` * ${pkFieldName}: 'some-id',`); - docLines.push(` * scope: { parentId: 'parent-id' },`); - docLines.push(` * });`); - docLines.push(` * \`\`\``); + docLines.push(''); + docLines.push('@example With scope for hierarchical cache invalidation'); + docLines.push('```tsx'); + docLines.push(`const { data } = ${hookName}({`); + docLines.push(` ${pkFieldName}: 'some-id',`); + docLines.push(" scope: { parentId: 'parent-id' },"); + docLines.push('});'); + docLines.push('```'); } - docLines.push(` */`); - lines.push(...docLines); - - const singleOptionsType = (queryData: string, data: string) => - hasRelationships && useCentralizedKeys - ? `Omit, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }` - : `Omit, 'queryKey' | 'queryFn'>`; - const singleImplOptionsType = hasRelationships && useCentralizedKeys - ? `Omit, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }` - : `Omit, 'queryKey' | 'queryFn'>`; - - // Overload 1: with selection.fields (provides contextual typing for autocompletion) - lines.push(`export function ${hookName}(`); - lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection: ${selectionWithFieldsType('S')} } & ${singleOptionsType(singleResultType('S'), 'TData')}`); - lines.push(`): UseQueryResult;`); - - // Overload 2: without fields (uses default select) - lines.push(`export function ${hookName}(`); - lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection?: ${selectionWithoutFieldsType()} } & ${singleOptionsType(singleResultType('typeof defaultSelect'), 'TData')}`); - lines.push(`): UseQueryResult;`); + + // Overload 1: with fields + const o1Props = [ + t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)), + t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(withFieldsSelectionType(sRef(), selectTypeName)) + ) + ]; + 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); + + // Overload 2: without fields + const o2SelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(withoutFieldsSelectionType()) + ); + o2SelProp.optional = true; + const o2Props = [ + t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)), + o2SelProp + ]; + const o2ParamType = t.tsIntersectionType([ + t.tsTypeLiteral(o2Props), + buildSingleOptionsType(singleResultTypeAST(typeofRef('defaultSelect')), typeRef('TData')) + ]); + statements.push( + exportDeclareFunction( + hookName, + createTDataTypeParam(singleResultTypeAST(typeofRef('defaultSelect'))), + [createFunctionParam('params', o2ParamType)], + typeRef('UseQueryResult', [typeRef('TData')]) + ) + ); // Implementation - lines.push(`export function ${hookName}(`); - lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection?: SelectionConfig<${selectTypeName}> } & ${singleImplOptionsType}`); - lines.push(`) {`); - lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params.selection);`); + const implSelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName))) + ); + implSelProp.optional = true; + const implProps = [ + t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)), + implSelProp + ]; + 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[] = []; + // const args = buildSelectionArgs(params.selection); + const argsCall = t.callExpression(t.identifier('buildSelectionArgs'), [ + t.memberExpression(t.identifier('params'), t.identifier('selection')) + ]); + // @ts-ignore + argsCall.typeParameters = t.tsTypeParameterInstantiation([typeRef(selectTypeName)]); + body.push(constDecl('args', argsCall)); + + const pkMemberExpr = t.memberExpression(t.identifier('params'), t.identifier(pkFieldName)); if (hasRelationships && useCentralizedKeys) { - lines.push(` const { scope, selection: _selection, ...queryOptions } = params ?? {};`); - lines.push(` void _selection;`); - lines.push(` return useQuery({`); - lines.push(` queryKey: ${keysName}.detail(params.${pkFieldName}, scope),`); - lines.push(` queryFn: () => getClient().${singularName}.findOne({ ${pkFieldName}: params.${pkFieldName}, ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - lines.push(` ...queryOptions,`); - lines.push(` });`); - } else if (useCentralizedKeys) { - lines.push(` const { selection: _selection, ...queryOptions } = params ?? {};`); - lines.push(` void _selection;`); - lines.push(` return useQuery({`); - lines.push(` queryKey: ${keysName}.detail(params.${pkFieldName}),`); - lines.push(` queryFn: () => getClient().${singularName}.findOne({ ${pkFieldName}: params.${pkFieldName}, ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - lines.push(` ...queryOptions,`); - lines.push(` });`); + body.push(destructureParamsWithSelectionAndScope('queryOptions')); + body.push(voidStatement('_selection')); + body.push(returnUseQuery( + buildDetailQueryKey(pkMemberExpr, t.identifier('scope')), + buildFindOneFn(), + [spreadObj(t.identifier('queryOptions'))] + )); } else { - lines.push(` const { selection: _selection, ...queryOptions } = params ?? {};`); - lines.push(` void _selection;`); - lines.push(` return useQuery({`); - lines.push(` queryKey: ${queryName}QueryKey(params.${pkFieldName}),`); - lines.push(` queryFn: () => getClient().${singularName}.findOne({ ${pkFieldName}: params.${pkFieldName}, ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - lines.push(` ...queryOptions,`); - lines.push(` });`); + body.push(destructureParamsWithSelection('queryOptions')); + body.push(voidStatement('_selection')); + body.push(returnUseQuery( + buildDetailQueryKey(pkMemberExpr), + buildFindOneFn(), + [spreadObj(t.identifier('queryOptions'))] + )); } - lines.push(`}`); - lines.push(''); + statements.push(exportFunction(hookName, null, [createFunctionParam('params', implParamType)], body)); } // Fetch function - lines.push(`/**`); - lines.push(` * Fetch a single ${typeName} without React hooks`); - lines.push(` *`); - lines.push(` * @example`); - lines.push(` * \`\`\`ts`); - lines.push(` * const data = await fetch${ucFirst(singularName)}Query({`); - lines.push(` * ${pkFieldName}: 'some-id',`); - lines.push(` * selection: { fields: { id: true } },`); - lines.push(` * });`); - lines.push(` * \`\`\``); - lines.push(` */`); - lines.push(`export async function fetch${ucFirst(singularName)}Query(`); - lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection: ${selectionWithFieldsType('S')} }`); - lines.push(`): Promise<${singleResultType('S')}>;`); - lines.push(`export async function fetch${ucFirst(singularName)}Query(`); - lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection?: ${selectionWithoutFieldsType()} },`); - lines.push(`): Promise<${singleResultType('typeof defaultSelect')}>;`); - lines.push(`export async function fetch${ucFirst(singularName)}Query(`); - lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection?: SelectionConfig<${selectTypeName}> },`); - lines.push(`) {`); - lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params.selection);`); - lines.push(` return getClient().${singularName}.findOne({ ${pkFieldName}: params.${pkFieldName}, ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap();`); - lines.push(`}`); - lines.push(''); + 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); + + // Overload 2: without fields + const f2SelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(withoutFieldsSelectionType()) + ); + f2SelProp.optional = true; + const f2Props = [ + t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)), + f2SelProp + ]; + statements.push( + exportAsyncDeclareFunction( + fetchFnName, + null, + [createFunctionParam('params', t.tsTypeLiteral(f2Props))], + typeRef('Promise', [singleResultTypeAST(typeofRef('defaultSelect'))]) + ) + ); + + // Implementation + const fImplSelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName))) + ); + fImplSelProp.optional = true; + const fImplProps = [ + t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)), + fImplSelProp + ]; + const fBody: t.Statement[] = []; + const fArgsCall = t.callExpression(t.identifier('buildSelectionArgs'), [ + t.memberExpression(t.identifier('params'), t.identifier('selection')) + ]); + // @ts-ignore + fArgsCall.typeParameters = t.tsTypeParameterInstantiation([typeRef(selectTypeName)]); + fBody.push(constDecl('args', fArgsCall)); + fBody.push(t.returnStatement(buildFindOneCallExpr(singularName, pkFieldName, 'args', selectTypeName))); + statements.push(exportAsyncFunction(fetchFnName, null, [createFunctionParam('params', t.tsTypeLiteral(fImplProps))], fBody)); + } // Prefetch function if (reactQueryEnabled) { - lines.push(`/**`); - lines.push(` * Prefetch a single ${typeName} for SSR or cache warming`); - lines.push(` *`); - lines.push(` * @example`); - lines.push(` * \`\`\`ts`); - lines.push(` * await prefetch${ucFirst(singularName)}Query(queryClient, { ${pkFieldName}: 'some-id' });`); - lines.push(` * \`\`\``); - lines.push(` */`); - lines.push(`export async function prefetch${ucFirst(singularName)}Query(`); - lines.push(` queryClient: QueryClient,`); - lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection: ${selectionWithFieldsType('S')} }${hasRelationships && useCentralizedKeys ? ` & { scope?: ${scopeTypeName} }` : ''},`); - if (hasRelationships && useCentralizedKeys) { - // scope is included in params above - } - lines.push(`): Promise;`); - lines.push(`export async function prefetch${ucFirst(singularName)}Query(`); - lines.push(` queryClient: QueryClient,`); - lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection?: ${selectionWithoutFieldsType()} }${hasRelationships && useCentralizedKeys ? ` & { scope?: ${scopeTypeName} }` : ''},`); - lines.push(`): Promise;`); - lines.push(`export async function prefetch${ucFirst(singularName)}Query(`); - lines.push(` queryClient: QueryClient,`); - lines.push(` params: { ${pkFieldName}: ${pkFieldTsType}; selection?: SelectionConfig<${selectTypeName}> }${hasRelationships && useCentralizedKeys ? ` & { scope?: ${scopeTypeName} }` : ''},`); - lines.push(`): Promise {`); - lines.push(` const args = buildSelectionArgs<${selectTypeName}>(params.selection);`); + const prefetchFnName = `prefetch${ucFirst(singularName)}Query`; - if (hasRelationships && useCentralizedKeys) { - lines.push(` await queryClient.prefetchQuery({`); - lines.push(` queryKey: ${keysName}.detail(params.${pkFieldName}, params.scope),`); - lines.push(` queryFn: () => getClient().${singularName}.findOne({ ${pkFieldName}: params.${pkFieldName}, ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - lines.push(` });`); - } else if (useCentralizedKeys) { - lines.push(` await queryClient.prefetchQuery({`); - lines.push(` queryKey: ${keysName}.detail(params.${pkFieldName}),`); - lines.push(` queryFn: () => getClient().${singularName}.findOne({ ${pkFieldName}: params.${pkFieldName}, ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - lines.push(` });`); - } else { - lines.push(` await queryClient.prefetchQuery({`); - lines.push(` queryKey: ${queryName}QueryKey(params.${pkFieldName}),`); - lines.push(` queryFn: () => getClient().${singularName}.findOne({ ${pkFieldName}: params.${pkFieldName}, ...(args ?? {}), select: (args?.select ?? defaultSelect) as ${selectTypeName} }).unwrap(),`); - lines.push(` });`); - } + // 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()]) + ); + addJSDocComment(p1Decl, [ + `Prefetch a single ${typeName} for SSR or cache warming`, + '', + '@example', + '```ts', + `await ${prefetchFnName}(queryClient, { ${pkFieldName}: 'some-id' });`, + '```' + ]); + statements.push(p1Decl); + + // Overload 2: without fields + const p2SelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(withoutFieldsSelectionType()) + ); + p2SelProp.optional = true; + const p2Props: t.TSPropertySignature[] = [ + t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)), + p2SelProp + ]; + const p2ParamType = hasRelationships && useCentralizedKeys + ? t.tsIntersectionType([t.tsTypeLiteral(p2Props), scopeTypeLiteral(scopeTypeName)]) + : t.tsTypeLiteral(p2Props); + statements.push( + exportAsyncDeclareFunction( + prefetchFnName, + null, + [createFunctionParam('queryClient', typeRef('QueryClient')), createFunctionParam('params', p2ParamType)], + typeRef('Promise', [t.tsVoidKeyword()]) + ) + ); - lines.push(`}`); + // Implementation + const pImplSelProp = t.tsPropertySignature( + t.identifier('selection'), + t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName))) + ); + pImplSelProp.optional = true; + const pImplProps: t.TSPropertySignature[] = [ + t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)), + pImplSelProp + ]; + const pImplParamType = hasRelationships && useCentralizedKeys + ? t.tsIntersectionType([t.tsTypeLiteral(pImplProps), scopeTypeLiteral(scopeTypeName)]) + : t.tsTypeLiteral(pImplProps); + + const pBody: t.Statement[] = []; + const pArgsCall = t.callExpression(t.identifier('buildSelectionArgs'), [ + t.memberExpression(t.identifier('params'), t.identifier('selection')) + ]); + // @ts-ignore + pArgsCall.typeParameters = t.tsTypeParameterInstantiation([typeRef(selectTypeName)]); + pBody.push(constDecl('args', pArgsCall)); + + 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, + t.tsVoidKeyword() + ) + ); } const headerText = reactQueryEnabled ? `Single item query hook for ${typeName}` : `Single item query functions for ${typeName}`; - const content = getGeneratedFileHeader(headerText) + '\n\n' + lines.join('\n') + '\n'; return { fileName: getSingleQueryFileName(table), - content + content: generateHookFileCode(headerText, statements) }; } diff --git a/graphql/codegen/src/core/codegen/selection.ts b/graphql/codegen/src/core/codegen/selection.ts index e205f3ca4..e9cd7fe3c 100644 --- a/graphql/codegen/src/core/codegen/selection.ts +++ b/graphql/codegen/src/core/codegen/selection.ts @@ -1,87 +1,39 @@ /** * Selection helper generator for React Query hooks * - * Generates selection.ts as a shared adapter layer between hook-facing - * `selection` params and ORM-facing args (`select`, `where`, `orderBy`, etc.). + * Uses template-copy pattern: reads hooks-selection.ts from templates/ + * and writes it to the output directory with a generated file header. */ -import { getGeneratedFileHeader } from './utils'; - -/** - * Generate selection.ts content - shared selection types + runtime mappers - */ -export function generateSelectionFile(): string { - const header = getGeneratedFileHeader('Selection helpers for React Query hooks'); - - const code = ` -export interface SelectionConfig { - fields?: TFields; -} +import * as fs from 'fs'; +import * as path from 'path'; -export interface ListSelectionConfig - extends SelectionConfig { - where?: TWhere; - orderBy?: TOrderBy[]; - first?: number; - last?: number; - after?: string; - before?: string; - offset?: number; -} +import { getGeneratedFileHeader } from './utils'; -export function buildSelectionArgs( - selection?: SelectionConfig -): { select?: TFields } | undefined { - if (!selection || selection.fields === undefined) { - return undefined; +function findTemplateFile(templateName: string): string { + const templatePath = path.join(__dirname, 'templates', templateName); + if (fs.existsSync(templatePath)) { + return templatePath; } - - return { select: selection.fields }; + throw new Error( + `Could not find template file: ${templateName}. Searched in: ${templatePath}` + ); } -export function buildListSelectionArgs( - selection?: ListSelectionConfig -): - | { - select?: TFields; - where?: TWhere; - orderBy?: TOrderBy[]; - first?: number; - last?: number; - after?: string; - before?: string; - offset?: number; - } - | undefined { - if (!selection) { - return undefined; - } - - const hasAnyValues = - selection.fields !== undefined || - selection.where !== undefined || - selection.orderBy !== undefined || - selection.first !== undefined || - selection.last !== undefined || - selection.after !== undefined || - selection.before !== undefined || - selection.offset !== undefined; - - if (!hasAnyValues) { - return undefined; - } - - 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 - }; +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; } -`; - return header + '\n\n' + code.trim() + '\n'; +/** + * 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/templates/hooks-client.ts b/graphql/codegen/src/core/codegen/templates/hooks-client.ts new file mode 100644 index 000000000..197fad4c5 --- /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..4e2741476 --- /dev/null +++ b/graphql/codegen/src/core/codegen/templates/hooks-selection.ts @@ -0,0 +1,79 @@ +/** + * 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 + extends SelectionConfig { + where?: TWhere; + orderBy?: TOrderBy[]; + first?: number; + last?: number; + after?: string; + before?: string; + offset?: number; +} + +export function buildSelectionArgs( + selection?: SelectionConfig +): { select?: TFields } | undefined { + if (!selection || selection.fields === undefined) { + return undefined; + } + + 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; + } + | undefined { + if (!selection) { + return undefined; + } + + const hasAnyValues = + selection.fields !== undefined || + selection.where !== undefined || + selection.orderBy !== undefined || + selection.first !== undefined || + selection.last !== undefined || + selection.after !== undefined || + selection.before !== undefined || + selection.offset !== undefined; + + if (!hasAnyValues) { + return undefined; + } + + 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 + }; +} From 13c06dfc86730a222a63ab5b62f193cfaef57b41 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sat, 7 Feb 2026 22:51:28 +0000 Subject: [PATCH 08/17] refactor(cli): simplify arg parsing with generic transforms, remove --browser-compatible - Add hyphenateKeys, flattenDbFields, buildDbConfig, seedArgvFromConfig, buildGenerateOptions to shared.ts as generic reusable utilities - Replace manual cliOverrides/hasNonInteractiveArgs with prompt->camelize->generate flow - Remove deprecated --browser-compatible flag from CLI, config types, and generate - Simplify both CLI entry points (graphql/codegen/src/cli, packages/cli) - Update test mocks to match new shared utility imports --- graphql/codegen/src/cli/index.ts | 127 ++++--------------------- graphql/codegen/src/cli/shared.ts | 95 ++++++++++++------ graphql/codegen/src/core/generate.ts | 7 -- graphql/codegen/src/index.ts | 13 ++- graphql/codegen/src/types/config.ts | 9 -- packages/cli/__tests__/codegen.test.ts | 16 +++- packages/cli/src/commands/codegen.ts | 113 +++------------------- 7 files changed, 118 insertions(+), 262 deletions(-) diff --git a/graphql/codegen/src/cli/index.ts b/graphql/codegen/src/cli/index.ts index ad499af48..cfea02a20 100644 --- a/graphql/codegen/src/cli/index.ts +++ b/graphql/codegen/src/cli/index.ts @@ -5,17 +5,18 @@ * This is a thin wrapper around the core generate() function. * All business logic is in the core modules. */ -import { CLI, CLIOptions, getPackageJson,Inquirerer } from 'inquirerer'; +import { CLI, CLIOptions, getPackageJson, Inquirerer } from 'inquirerer'; import { findConfigFile, loadConfigFile } from '../core/config'; import { generate } from '../core/generate'; import type { GraphQLSDKConfigTarget } from '../types/config'; import { + buildDbConfig, + buildGenerateOptions, camelizeArgv, - type CodegenAnswers, codegenQuestions, printResult, - splitCommas + seedArgvFromConfig } from './shared'; const usage = ` @@ -39,7 +40,6 @@ Generator Options: -o, --output Output directory -t, --target Target name (for multi-target configs) -a, --authorization Authorization header value - --browser-compatible Deprecated no-op (retained for compatibility) --dry-run Preview without writing files -v, --verbose Show detailed output @@ -63,50 +63,16 @@ export const commands = async ( process.exit(0); } - const hasSourceCliFlags = Boolean( - argv.endpoint || - argv.e || - argv['schema-file'] || - argv.s || - argv.schemas || - argv['api-names'] + 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 autoConfigPath = !explicitConfigPath && !hasSourceCliFlags - ? findConfigFile() - : undefined; - const configPath = (explicitConfigPath || autoConfigPath) as string | undefined; + const configPath = explicitConfigPath || (!hasSourceFlags ? findConfigFile() : undefined); const targetName = (argv.target || argv.t) as string | undefined; - // Collect CLI flags that should override config file settings - const cliOverrides: Partial = {}; - const endpoint = (argv.endpoint || argv.e) as string | undefined; - const schemaFile = (argv['schema-file'] || argv.s) as string | undefined; - const schemas = splitCommas(argv.schemas as string | undefined); - const apiNames = splitCommas(argv['api-names'] as string | undefined); - if (endpoint) { - cliOverrides.endpoint = endpoint; - cliOverrides.schemaFile = undefined; - cliOverrides.db = undefined; - } - if (schemaFile) { - cliOverrides.schemaFile = schemaFile; - cliOverrides.endpoint = undefined; - cliOverrides.db = undefined; - } - if (schemas || apiNames) { - cliOverrides.db = { schemas, apiNames }; - cliOverrides.endpoint = undefined; - cliOverrides.schemaFile = undefined; - } - if (argv['react-query'] === true || argv.reactQuery === true) cliOverrides.reactQuery = true; - if (argv.orm === true) cliOverrides.orm = true; - if (argv.verbose === true || argv.v === true) cliOverrides.verbose = true; - if (argv['dry-run'] === true || argv.dryRun === true) cliOverrides.dryRun = true; - if (argv.output || argv.o) cliOverrides.output = (argv.output || argv.o) as string; - if (argv.authorization || argv.a) cliOverrides.authorization = (argv.authorization || argv.a) as string; - - // If config file exists, load and run + let fileConfig: GraphQLSDKConfigTarget = {}; + if (configPath) { const loaded = await loadConfigFile(configPath); if (!loaded.success) { @@ -115,12 +81,9 @@ 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); if (isMulti) { - // Multi-target: simple for loop over targets const targets = config as Record; const names = targetName ? [targetName] : Object.keys(targets); @@ -129,10 +92,11 @@ export const commands = async ( process.exit(1); } + const cliOptions = buildDbConfig(camelizeArgv(argv as Record)); let hasError = false; for (const name of names) { console.log(`\n[${name}]`); - const result = await generate({ ...targets[name], ...cliOverrides }); + const result = await generate({ ...targets[name], ...cliOptions } as GraphQLSDKConfigTarget); printResult(result); if (!result.success) hasError = true; } @@ -142,68 +106,13 @@ export const commands = async ( return argv; } - // Single config — merge CLI overrides - const result = await generate({ ...(config as GraphQLSDKConfigTarget), ...cliOverrides }); - printResult(result); - if (!result.success) process.exit(1); - prompter.close(); - return argv; + fileConfig = config as GraphQLSDKConfigTarget; } - const hasNonInteractiveArgs = Boolean( - endpoint || - schemaFile || - schemas || - apiNames || - argv['react-query'] === true || - argv.reactQuery === true || - argv.orm === true || - argv.output || - argv.o || - argv.authorization || - argv.a || - argv['dry-run'] === true || - argv.dryRun === true || - argv.verbose === true || - argv.v === true || - argv['browser-compatible'] !== undefined || - argv.browserCompatible !== undefined - ); - - if (hasNonInteractiveArgs) { - const result = await generate({ - ...cliOverrides - }); - printResult(result); - prompter.close(); - return argv; - } - - // 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 = await prompter.prompt(seeded, codegenQuestions); + const options = buildGenerateOptions(answers, fileConfig); + const result = await generate(options); printResult(result); prompter.close(); return argv; @@ -222,7 +131,7 @@ export const options: Partial = { v: 'verbose' }, boolean: [ - 'help', 'version', 'verbose', 'dry-run', 'react-query', 'orm', 'keep-db', 'browser-compatible' + 'help', 'version', 'verbose', 'dry-run', 'react-query', 'orm', 'keep-db' ], string: [ 'config', 'endpoint', 'schema-file', 'output', 'target', 'authorization', diff --git a/graphql/codegen/src/cli/shared.ts b/graphql/codegen/src/cli/shared.ts index 87a55bac9..26370919b 100644 --- a/graphql/codegen/src/cli/shared.ts +++ b/graphql/codegen/src/cli/shared.ts @@ -1,27 +1,21 @@ /** * 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 { camelize } from 'inflekt'; import { inflektTree } from 'inflekt/transform-keys'; import type { Question } from 'inquirerer'; import type { GenerateResult } from '../core/generate'; +import type { GraphQLSDKConfigTarget } from '../types/config'; -/** - * Sanitize function that splits comma-separated strings into arrays - */ export const splitCommas = (input: string | undefined): string[] | undefined => { if (!input) return undefined; 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 - */ export interface CodegenAnswers { endpoint?: string; schemaFile?: string; @@ -30,15 +24,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', @@ -90,14 +80,6 @@ export const codegenQuestions: Question[] = [ default: false, useDefault: true }, - { - name: 'browser-compatible', - message: 'Browser-compatible mode (deprecated no-op)?', - type: 'confirm', - required: false, - default: true, - useDefault: true - }, { name: 'authorization', message: 'Authorization header value', @@ -122,9 +104,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); @@ -138,15 +117,69 @@ export function printResult(result: GenerateResult): void { } } +// ============================================================================ +// Key transform utilities +// ============================================================================ + const isTopLevel = (_key: string, path: string[]) => path.length === 0; -export const camelizeArgv = (argv: Record) => +const skipNonTopLevel = (key: string, path: string[]) => + !isTopLevel(key, path) || key === '_' || key.startsWith('_'); + +export const camelizeArgv = (argv: Record): 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('_') + }, { 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; +} + +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 withDb = buildDbConfig(camelized); + return { ...fileConfig, ...withDb } as GraphQLSDKConfigTarget; +} diff --git a/graphql/codegen/src/core/generate.ts b/graphql/codegen/src/core/generate.ts index f3f63b948..e73b34edc 100644 --- a/graphql/codegen/src/core/generate.ts +++ b/graphql/codegen/src/core/generate.ts @@ -43,13 +43,6 @@ export async function generate(options: GenerateOptions = {}): Promise { 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) => { @@ -38,6 +38,14 @@ jest.mock('@constructive-io/graphql-codegen', () => { } }), camelizeArgv: jest.fn((argv: Record) => argv), + seedArgvFromConfig: jest.fn((argv: Record, _fileConfig: any) => argv), + buildGenerateOptions: jest.fn((answers: Record, _fileConfig: any) => { + const { schemas, apiNames, ...rest } = answers; + if (schemas || apiNames) { + return { ...rest, db: { schemas, apiNames } }; + } + return rest; + }), }; }) diff --git a/packages/cli/src/commands/codegen.ts b/packages/cli/src/commands/codegen.ts index d532b946f..391807fb0 100644 --- a/packages/cli/src/commands/codegen.ts +++ b/packages/cli/src/commands/codegen.ts @@ -5,9 +5,8 @@ import { loadConfigFile, codegenQuestions, printResult, - camelizeArgv, - splitCommas, - type CodegenAnswers, + buildGenerateOptions, + seedArgvFromConfig, type GraphQLSDKConfigTarget, } from '@constructive-io/graphql-codegen'; @@ -30,7 +29,6 @@ Generator Options: --orm Generate ORM client --output Output directory (default: codegen) --authorization Authorization header value - --browser-compatible Deprecated no-op (retained for compatibility) --dry-run Preview without writing files --verbose Verbose output @@ -47,52 +45,13 @@ export default async ( process.exit(0); } - const hasSourceCliFlags = Boolean( - argv.endpoint || - argv['schema-file'] || - argv.schemaFile || - argv.schemas || - argv['api-names'] || - argv.apiNames + const hasSourceFlags = Boolean( + argv.endpoint || argv['schema-file'] || argv.schemas || argv['api-names'] ); - const explicitConfigPath = argv.config as string | undefined; - const autoConfigPath = !explicitConfigPath && !hasSourceCliFlags - ? findConfigFile() - : undefined; - const configPath = explicitConfigPath || autoConfigPath; + const configPath = (argv.config as string | undefined) || + (!hasSourceFlags ? findConfigFile() : undefined); - const endpoint = argv.endpoint as string | undefined; - const schemaFile = (argv['schema-file'] || argv.schemaFile) as string | undefined; - const schemas = splitCommas(argv.schemas as string | undefined); - const apiNames = splitCommas((argv['api-names'] || argv.apiNames) as string | undefined); - - const cliOverrides: Partial = {}; - if (endpoint) { - cliOverrides.endpoint = endpoint; - cliOverrides.schemaFile = undefined; - cliOverrides.db = undefined; - } - if (schemaFile) { - cliOverrides.schemaFile = schemaFile; - cliOverrides.endpoint = undefined; - cliOverrides.db = undefined; - } - if (schemas || apiNames) { - cliOverrides.db = { schemas, apiNames }; - cliOverrides.endpoint = undefined; - cliOverrides.schemaFile = undefined; - } - if (argv['react-query'] === true || argv.reactQuery === true) cliOverrides.reactQuery = true; - if (argv.orm === true) cliOverrides.orm = true; - if (argv.verbose === true) cliOverrides.verbose = true; - if (argv['dry-run'] === true || argv.dryRun === true) cliOverrides.dryRun = true; - if (argv.output) cliOverrides.output = argv.output as string; - if (argv.authorization) cliOverrides.authorization = argv.authorization as string; - if (argv['browser-compatible'] !== undefined) { - cliOverrides.browserCompatible = argv['browser-compatible'] as boolean; - } else if (argv.browserCompatible !== undefined) { - cliOverrides.browserCompatible = argv.browserCompatible as boolean; - } + let fileConfig: GraphQLSDKConfigTarget = {}; if (configPath) { const loaded = await loadConfigFile(configPath); @@ -100,60 +59,12 @@ export default async ( console.error('x', loaded.error); process.exit(1); } - const result = await generate({ - ...(loaded.config as GraphQLSDKConfigTarget), - ...cliOverrides, - }); - printResult(result); - return; - } - - const hasNonInteractiveArgs = Boolean( - endpoint || - schemaFile || - schemas || - apiNames || - argv['react-query'] === true || - argv.reactQuery === true || - argv.orm === true || - argv.output || - argv.authorization || - argv['dry-run'] === true || - argv.dryRun === true || - argv.verbose === true || - argv['browser-compatible'] !== undefined || - argv.browserCompatible !== undefined - ); - - if (hasNonInteractiveArgs) { - const result = await generate({ ...cliOverrides }); - printResult(result); - return; + fileConfig = loaded.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); - - // 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 as Record, fileConfig); + const answers = await prompter.prompt(seeded, codegenQuestions); + const options = buildGenerateOptions(answers, fileConfig); + const result = await generate(options); printResult(result); }; From 5eb1b8e4f2836d39de506a1288b561d72b01cad8 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sat, 7 Feb 2026 23:45:11 +0000 Subject: [PATCH 09/17] refactor(codegen): remove default selects entirely (Path A) - Remove all defaultSelect constants and overload 2 (without fields) from all hook generators - Remove buildDefaultSelectExpr, buildSelectFallbackExpr, buildDefaultSelectLiteral, getDefaultSelectFieldName - Remove withoutFieldsSelectionType, withoutFieldsListSelectionType, NON_SELECT_TYPES_AST - Remove buildDefaultSelectExpression from ORM custom-ops-generator - Remove defaultSelect/defaultRef from ORM model-generator - Make selection with fields required in all hook and ORM method signatures - Update 25 snapshots to reflect removed overloads --- .../model-generator.test.ts.snap | 167 +---- .../react-query-hooks.test.ts.snap | 668 +++--------------- .../src/core/codegen/custom-mutations.ts | 48 +- .../src/core/codegen/custom-queries.ts | 103 +-- graphql/codegen/src/core/codegen/hooks-ast.ts | 110 +-- graphql/codegen/src/core/codegen/mutations.ts | 95 +-- .../core/codegen/orm/custom-ops-generator.ts | 137 +--- graphql/codegen/src/core/codegen/orm/index.ts | 6 +- .../src/core/codegen/orm/model-generator.ts | 106 +-- graphql/codegen/src/core/codegen/queries.ts | 156 +--- .../src/core/codegen/select-helpers.ts | 41 +- graphql/codegen/src/core/codegen/utils.ts | 30 - 12 files changed, 186 insertions(+), 1481 deletions(-) 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 4ed4ce22b..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 @@ -11,9 +11,6 @@ import { QueryBuilder, buildFindManyDocument, buildFindFirstDocument, buildFindO 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"; -const defaultSelect = { - id: true -} as const; export class UserModel { constructor(private client: OrmClient) {} findMany(args: FindManyArgs & { @@ -21,16 +18,11 @@ export class UserModel { } & StrictSelect): QueryBuilder<{ users: ConnectionResult>; }>; - findMany(args?: Omit, "select"> & { - select?: undefined; - }): QueryBuilder<{ - users: ConnectionResult>; - }>; - findMany(args?: FindManyArgs) { + findMany(args: FindManyArgs) { const { document, variables - } = buildFindManyDocument("User", "users", args?.select ?? defaultSelect, { + } = buildFindManyDocument("User", "users", args.select, { where: args?.where, orderBy: args?.orderBy as string[] | undefined, first: args?.first, @@ -55,18 +47,11 @@ export class UserModel { nodes: InferSelectResult[]; }; }>; - findFirst(args?: Omit, "select"> & { - select?: undefined; - }): QueryBuilder<{ - users: { - nodes: InferSelectResult[]; - }; - }>; - findFirst(args?: FindFirstArgs) { + findFirst(args: FindFirstArgs) { const { document, variables - } = buildFindFirstDocument("User", "users", args?.select ?? defaultSelect, { + } = buildFindFirstDocument("User", "users", args.select, { where: args?.where }, "UserFilter", connectionFieldsMap); return new QueryBuilder({ @@ -86,17 +71,12 @@ export class UserModel { }>; findOne(args: { id: string; - }): QueryBuilder<{ - user: InferSelectResult | null; - }>; - findOne(args: { - id: string; - select?: UserSelect; + select: UserSelect; }) { const { document, variables - } = buildFindOneDocument("User", "user", args.id, args.select ?? defaultSelect, "id", "UUID!", connectionFieldsMap); + } = buildFindOneDocument("User", "user", args.id, args.select, "id", "UUID!", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "query", @@ -113,18 +93,11 @@ export class UserModel { user: InferSelectResult; }; }>; - create(args: Omit, "select"> & { - select?: undefined; - }): QueryBuilder<{ - createUser: { - user: InferSelectResult; - }; - }>; create(args: CreateArgs) { const { document, variables - } = buildCreateDocument("User", "createUser", "user", args.select ?? defaultSelect, args.data, "CreateUserInput", connectionFieldsMap); + } = buildCreateDocument("User", "createUser", "user", args.select, args.data, "CreateUserInput", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -143,22 +116,13 @@ export class UserModel { user: InferSelectResult; }; }>; - update(args: Omit, "select"> & { - select?: undefined; - }): QueryBuilder<{ - updateUser: { - user: InferSelectResult; - }; - }>; update(args: UpdateArgs) { const { document, variables - } = buildUpdateByPkDocument("User", "updateUser", "user", args.select ?? defaultSelect, args.where.id, args.data, "UpdateUserInput", "id", connectionFieldsMap); + } = buildUpdateByPkDocument("User", "updateUser", "user", args.select, args.where.id, args.data, "UpdateUserInput", "id", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -177,22 +141,13 @@ export class UserModel { user: InferSelectResult; }; }>; - delete(args: Omit, "select"> & { - select?: undefined; - }): QueryBuilder<{ - deleteUser: { - user: InferSelectResult; - }; - }>; delete(args: DeleteArgs<{ id: string; }, UserSelect>) { const { document, variables - } = buildDeleteByPkDocument("User", "deleteUser", "user", args.where.id, "DeleteUserInput", "id", args.select ?? defaultSelect, connectionFieldsMap); + } = buildDeleteByPkDocument("User", "deleteUser", "user", args.where.id, "DeleteUserInput", "id", args.select, connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -216,9 +171,6 @@ import { QueryBuilder, buildFindManyDocument, buildFindFirstDocument, buildFindO 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"; -const defaultSelect = { - id: true -} as const; export class AuditLogModel { constructor(private client: OrmClient) {} findMany(args: FindManyArgs & { @@ -226,16 +178,11 @@ export class AuditLogModel { } & StrictSelect): QueryBuilder<{ auditLogs: ConnectionResult>; }>; - findMany(args?: Omit, "select"> & { - select?: undefined; - }): QueryBuilder<{ - auditLogs: ConnectionResult>; - }>; - findMany(args?: FindManyArgs) { + findMany(args: FindManyArgs) { const { document, variables - } = buildFindManyDocument("AuditLog", "auditLogs", args?.select ?? defaultSelect, { + } = buildFindManyDocument("AuditLog", "auditLogs", args.select, { where: args?.where, orderBy: args?.orderBy as string[] | undefined, first: args?.first, @@ -260,18 +207,11 @@ export class AuditLogModel { nodes: InferSelectResult[]; }; }>; - findFirst(args?: Omit, "select"> & { - select?: undefined; - }): QueryBuilder<{ - auditLogs: { - nodes: InferSelectResult[]; - }; - }>; - findFirst(args?: FindFirstArgs) { + findFirst(args: FindFirstArgs) { const { document, variables - } = buildFindFirstDocument("AuditLog", "auditLogs", args?.select ?? defaultSelect, { + } = buildFindFirstDocument("AuditLog", "auditLogs", args.select, { where: args?.where }, "AuditLogFilter", connectionFieldsMap); return new QueryBuilder({ @@ -291,17 +231,12 @@ export class AuditLogModel { }>; findOne(args: { id: string; - }): QueryBuilder<{ - auditLog: InferSelectResult | null; - }>; - findOne(args: { - id: string; - select?: AuditLogSelect; + select: AuditLogSelect; }) { const { document, variables - } = buildFindOneDocument("AuditLog", "auditLog", args.id, args.select ?? defaultSelect, "id", "UUID!", connectionFieldsMap); + } = buildFindOneDocument("AuditLog", "auditLog", args.id, args.select, "id", "UUID!", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "query", @@ -318,18 +253,11 @@ export class AuditLogModel { auditLog: InferSelectResult; }; }>; - create(args: Omit, "select"> & { - select?: undefined; - }): QueryBuilder<{ - createAuditLog: { - auditLog: InferSelectResult; - }; - }>; create(args: CreateArgs) { const { document, variables - } = buildCreateDocument("AuditLog", "createAuditLog", "auditLog", args.select ?? defaultSelect, args.data, "CreateAuditLogInput", connectionFieldsMap); + } = buildCreateDocument("AuditLog", "createAuditLog", "auditLog", args.select, args.data, "CreateAuditLogInput", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -353,9 +281,6 @@ import { QueryBuilder, buildFindManyDocument, buildFindFirstDocument, buildFindO 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"; -const defaultSelect = { - id: true -} as const; export class OrganizationModel { constructor(private client: OrmClient) {} findMany(args: FindManyArgs & { @@ -363,16 +288,11 @@ export class OrganizationModel { } & StrictSelect): QueryBuilder<{ allOrganizations: ConnectionResult>; }>; - findMany(args?: Omit, "select"> & { - select?: undefined; - }): QueryBuilder<{ - allOrganizations: ConnectionResult>; - }>; - findMany(args?: FindManyArgs) { + findMany(args: FindManyArgs) { const { document, variables - } = buildFindManyDocument("Organization", "allOrganizations", args?.select ?? defaultSelect, { + } = buildFindManyDocument("Organization", "allOrganizations", args.select, { where: args?.where, orderBy: args?.orderBy as string[] | undefined, first: args?.first, @@ -397,18 +317,11 @@ export class OrganizationModel { nodes: InferSelectResult[]; }; }>; - findFirst(args?: Omit, "select"> & { - select?: undefined; - }): QueryBuilder<{ - allOrganizations: { - nodes: InferSelectResult[]; - }; - }>; - findFirst(args?: FindFirstArgs) { + findFirst(args: FindFirstArgs) { const { document, variables - } = buildFindFirstDocument("Organization", "allOrganizations", args?.select ?? defaultSelect, { + } = buildFindFirstDocument("Organization", "allOrganizations", args.select, { where: args?.where }, "OrganizationFilter", connectionFieldsMap); return new QueryBuilder({ @@ -428,17 +341,12 @@ export class OrganizationModel { }>; findOne(args: { id: string; - }): QueryBuilder<{ - organizationById: InferSelectResult | null; - }>; - findOne(args: { - id: string; - select?: OrganizationSelect; + select: OrganizationSelect; }) { const { document, variables - } = buildFindOneDocument("Organization", "organizationById", args.id, args.select ?? defaultSelect, "id", "UUID!", connectionFieldsMap); + } = buildFindOneDocument("Organization", "organizationById", args.id, args.select, "id", "UUID!", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "query", @@ -455,18 +363,11 @@ export class OrganizationModel { organization: InferSelectResult; }; }>; - create(args: Omit, "select"> & { - select?: undefined; - }): QueryBuilder<{ - registerOrganization: { - organization: InferSelectResult; - }; - }>; create(args: CreateArgs) { const { document, variables - } = buildCreateDocument("Organization", "registerOrganization", "organization", args.select ?? defaultSelect, args.data, "CreateOrganizationInput", connectionFieldsMap); + } = buildCreateDocument("Organization", "registerOrganization", "organization", args.select, args.data, "CreateOrganizationInput", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -485,22 +386,13 @@ export class OrganizationModel { organization: InferSelectResult; }; }>; - update(args: Omit, "select"> & { - select?: undefined; - }): QueryBuilder<{ - modifyOrganization: { - organization: InferSelectResult; - }; - }>; update(args: UpdateArgs) { const { document, variables - } = buildUpdateByPkDocument("Organization", "modifyOrganization", "organization", args.select ?? defaultSelect, args.where.id, args.data, "UpdateOrganizationInput", "id", connectionFieldsMap); + } = buildUpdateByPkDocument("Organization", "modifyOrganization", "organization", args.select, args.where.id, args.data, "UpdateOrganizationInput", "id", connectionFieldsMap); return new QueryBuilder({ client: this.client, operation: "mutation", @@ -519,22 +411,13 @@ export class OrganizationModel { organization: InferSelectResult; }; }>; - delete(args: Omit, "select"> & { - select?: undefined; - }): QueryBuilder<{ - removeOrganization: { - organization: InferSelectResult; - }; - }>; delete(args: DeleteArgs<{ id: string; }, OrganizationSelect>) { const { document, variables - } = buildDeleteByPkDocument("Organization", "removeOrganization", "organization", args.where.id, "DeleteOrganizationInput", "id", args.select ?? defaultSelect, connectionFieldsMap); + } = 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__/react-query-hooks.test.ts.snap b/graphql/codegen/src/__tests__/codegen/__snapshots__/react-query-hooks.test.ts.snap index 68b86cdec..fd0eeef96 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 @@ -198,9 +198,6 @@ 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"; -const defaultSelect = { - token: true -} as const; export function useLoginMutation(params: { selection: ({ fields: S; @@ -211,16 +208,7 @@ export function useLoginMutation(params: { login: InferSelectResult; }, Error, LoginVariables>; export function useLoginMutation(params?: { - selection?: ({ - fields?: undefined; - }); -} & Omit; -}, Error, LoginVariables>, "mutationFn">): UseMutationResult<{ - login: InferSelectResult; -}, Error, LoginVariables>; -export function useLoginMutation(params?: { - selection?: SelectionConfig; + selection: SelectionConfig; } & Omit, "mutationFn">) { const args = buildSelectionArgs(params?.selection); const { @@ -231,7 +219,7 @@ export function useLoginMutation(params?: { return useMutation({ mutationKey: customMutationKeys.login(), mutationFn: (variables: LoginVariables) => getClient().mutation.login(variables, { - select: (args?.select ?? defaultSelect) as LoginPayloadSelect + select: args.select }).unwrap(), ...mutationOptions }); @@ -257,9 +245,6 @@ import type { RegisterPayloadSelect, RegisterPayload } from "../../orm/input-typ import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; export type { RegisterVariables } from "../../orm/mutation"; export type { RegisterPayloadSelect } from "../../orm/input-types"; -const defaultSelect = { - token: true -} as const; export function useRegisterMutation(params: { selection: ({ fields: S; @@ -270,16 +255,7 @@ export function useRegisterMutation(params: { register: InferSelectResult; }, Error, RegisterVariables>; export function useRegisterMutation(params?: { - selection?: ({ - fields?: undefined; - }); -} & Omit; -}, Error, RegisterVariables>, "mutationFn">): UseMutationResult<{ - register: InferSelectResult; -}, Error, RegisterVariables>; -export function useRegisterMutation(params?: { - selection?: SelectionConfig; + selection: SelectionConfig; } & Omit, "mutationFn">) { const args = buildSelectionArgs(params?.selection); const { @@ -290,7 +266,7 @@ export function useRegisterMutation(params?: { return useMutation({ mutationKey: customMutationKeys.register(), mutationFn: (variables: RegisterVariables) => getClient().mutation.register(variables, { - select: (args?.select ?? defaultSelect) as RegisterPayloadSelect + select: args.select }).unwrap(), ...mutationOptions }); @@ -314,9 +290,6 @@ import { customMutationKeys } from "../mutation-keys"; import type { LogoutPayloadSelect, LogoutPayload } from "../../orm/input-types"; import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; export type { LogoutPayloadSelect } from "../../orm/input-types"; -const defaultSelect = { - success: true -} as const; export function useLogoutMutation(params: { selection: ({ fields: S; @@ -327,16 +300,7 @@ export function useLogoutMutation(params: { logout: InferSelectResult; }, Error, void>; export function useLogoutMutation(params?: { - selection?: ({ - fields?: undefined; - }); -} & Omit; -}, Error, void>, "mutationFn">): UseMutationResult<{ - logout: InferSelectResult; -}, Error, void>; -export function useLogoutMutation(params?: { - selection?: SelectionConfig; + selection: SelectionConfig; } & Omit, "mutationFn">) { const args = buildSelectionArgs(params?.selection); const { @@ -347,7 +311,7 @@ export function useLogoutMutation(params?: { return useMutation({ mutationKey: customMutationKeys.logout(), mutationFn: () => getClient().mutation.logout({ - select: (args?.select ?? defaultSelect) as LogoutPayloadSelect + select: args.select }).unwrap(), ...mutationOptions }); @@ -372,9 +336,6 @@ 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"; -const defaultSelect = { - token: true -} as const; export function useLoginMutation(params: { selection: ({ fields: S; @@ -385,16 +346,7 @@ export function useLoginMutation(params: { login: InferSelectResult; }, Error, LoginVariables>; export function useLoginMutation(params?: { - selection?: ({ - fields?: undefined; - }); -} & Omit; -}, Error, LoginVariables>, "mutationFn">): UseMutationResult<{ - login: InferSelectResult; -}, Error, LoginVariables>; -export function useLoginMutation(params?: { - selection?: SelectionConfig; + selection: SelectionConfig; } & Omit, "mutationFn">) { const args = buildSelectionArgs(params?.selection); const { @@ -404,7 +356,7 @@ export function useLoginMutation(params?: { void _selection; return useMutation({ mutationFn: (variables: LoginVariables) => getClient().mutation.login(variables, { - select: (args?.select ?? defaultSelect) as LoginPayloadSelect + select: args.select }).unwrap(), ...mutationOptions }); @@ -430,9 +382,6 @@ 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"; -const defaultSelect = { - id: true -} as const; /** Query key factory - re-exported from query-keys.ts */ export const searchUsersQueryKey = customQueryKeys.searchUsers; /** @@ -457,19 +406,9 @@ export function useSearchUsersQuery[]; }, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; -export function useSearchUsersQuery[]; -}>(params: { - variables: SearchUsersVariables; - selection?: ({ - fields?: undefined; - }); -} & Omit[]; -}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; export function useSearchUsersQuery(params: { variables: SearchUsersVariables; - selection?: SelectionConfig; + selection: SelectionConfig; } & Omit, "queryKey" | "queryFn">) { const variables = params?.variables; const args = buildSelectionArgs(params?.selection); @@ -483,7 +422,7 @@ export function useSearchUsersQuery(params: { return useQuery({ queryKey: searchUsersQueryKey(variables), queryFn: () => getClient().query.searchUsers(variables!, { - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(), enabled: !!variables && params?.enabled !== false, ...queryOptions @@ -507,20 +446,12 @@ export async function fetchSearchUsersQuery(params: { }>; export async function fetchSearchUsersQuery(params: { variables: SearchUsersVariables; - selection?: ({ - fields?: undefined; - }); -}): Promise<{ - searchUsers: InferSelectResult[]; -}>; -export async function fetchSearchUsersQuery(params: { - variables: SearchUsersVariables; - selection?: SelectionConfig; + selection: SelectionConfig; }) { const variables = params?.variables; const args = buildSelectionArgs(params?.selection); return getClient().query.searchUsers(variables!, { - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(); } /** @@ -539,20 +470,14 @@ export async function prefetchSearchUsersQuery(queryClient }): Promise; export async function prefetchSearchUsersQuery(queryClient: QueryClient, params: { variables: SearchUsersVariables; - selection?: ({ - fields?: undefined; - }); -}): Promise; -export async function prefetchSearchUsersQuery(queryClient: QueryClient, params: { - variables: SearchUsersVariables; - selection?: SelectionConfig; + selection: SelectionConfig; }): void { const variables = params?.variables; const args = buildSelectionArgs(params?.selection); await queryClient.prefetchQuery({ queryKey: searchUsersQueryKey(variables), queryFn: () => getClient().query.searchUsers(variables!, { - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap() }); } @@ -575,9 +500,6 @@ import { customQueryKeys } from "../query-keys"; import type { UserSelect, User } from "../../orm/input-types"; import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; export type { UserSelect } from "../../orm/input-types"; -const defaultSelect = { - id: true -} as const; /** Query key factory - re-exported from query-keys.ts */ export const currentUserQueryKey = customQueryKeys.currentUser; /** @@ -601,17 +523,8 @@ export function useCurrentUserQuery; }, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; -export function useCurrentUserQuery; -}>(params?: { - selection?: ({ - fields?: undefined; - }); -} & Omit; -}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; export function useCurrentUserQuery(params?: { - selection?: SelectionConfig; + selection: SelectionConfig; } & Omit, "queryKey" | "queryFn">) { const args = buildSelectionArgs(params?.selection); const { @@ -622,7 +535,7 @@ export function useCurrentUserQuery(params?: { return useQuery({ queryKey: currentUserQueryKey(), queryFn: () => getClient().query.currentUser({ - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(), ...queryOptions }); @@ -642,19 +555,12 @@ export async function fetchCurrentUserQuery(params: { }): Promise<{ currentUser: InferSelectResult; }>; -export async function fetchCurrentUserQuery(params?: { - selection?: ({ - fields?: undefined; - }); -}): Promise<{ - currentUser: InferSelectResult; -}>; -export async function fetchCurrentUserQuery(params?: { - selection?: SelectionConfig; +export async function fetchCurrentUserQuery(params: { + selection: SelectionConfig; }) { const args = buildSelectionArgs(params?.selection); return getClient().query.currentUser({ - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(); } /** @@ -670,19 +576,14 @@ export async function prefetchCurrentUserQuery(queryClient fields: S; } & StrictSelect); }): Promise; -export async function prefetchCurrentUserQuery(queryClient: QueryClient, params?: { - selection?: ({ - fields?: undefined; - }); -}): Promise; -export async function prefetchCurrentUserQuery(queryClient: QueryClient, params?: { - selection?: SelectionConfig; +export async function prefetchCurrentUserQuery(queryClient: QueryClient, params: { + selection: SelectionConfig; }): void { const args = buildSelectionArgs(params?.selection); await queryClient.prefetchQuery({ queryKey: currentUserQueryKey(), queryFn: () => getClient().query.currentUser({ - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap() }); } @@ -704,9 +605,6 @@ 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"; -const defaultSelect = { - id: true -} as const; /** Query key factory for caching */ export const currentUserQueryKey = () => ["currentUser"] as const; /** @@ -730,17 +628,8 @@ export function useCurrentUserQuery; }, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; -export function useCurrentUserQuery; -}>(params?: { - selection?: ({ - fields?: undefined; - }); -} & Omit; -}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; export function useCurrentUserQuery(params?: { - selection?: SelectionConfig; + selection: SelectionConfig; } & Omit, "queryKey" | "queryFn">) { const args = buildSelectionArgs(params?.selection); const { @@ -751,7 +640,7 @@ export function useCurrentUserQuery(params?: { return useQuery({ queryKey: currentUserQueryKey(), queryFn: () => getClient().query.currentUser({ - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(), ...queryOptions }); @@ -771,19 +660,12 @@ export async function fetchCurrentUserQuery(params: { }): Promise<{ currentUser: InferSelectResult; }>; -export async function fetchCurrentUserQuery(params?: { - selection?: ({ - fields?: undefined; - }); -}): Promise<{ - currentUser: InferSelectResult; -}>; -export async function fetchCurrentUserQuery(params?: { - selection?: SelectionConfig; +export async function fetchCurrentUserQuery(params: { + selection: SelectionConfig; }) { const args = buildSelectionArgs(params?.selection); return getClient().query.currentUser({ - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(); } /** @@ -799,19 +681,14 @@ export async function prefetchCurrentUserQuery(queryClient fields: S; } & StrictSelect); }): Promise; -export async function prefetchCurrentUserQuery(queryClient: QueryClient, params?: { - selection?: ({ - fields?: undefined; - }); -}): Promise; -export async function prefetchCurrentUserQuery(queryClient: QueryClient, params?: { - selection?: SelectionConfig; +export async function prefetchCurrentUserQuery(queryClient: QueryClient, params: { + selection: SelectionConfig; }): void { const args = buildSelectionArgs(params?.selection); await queryClient.prefetchQuery({ queryKey: currentUserQueryKey(), queryFn: () => getClient().query.currentUser({ - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap() }); } @@ -835,9 +712,6 @@ import { userMutationKeys } from "../mutation-keys"; 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"; -const defaultSelect = { - id: true -} as const; /** * Mutation hook for creating a User * @@ -863,21 +737,8 @@ export function useCreateUserMutation(params: { user: InferSelectResult; }; }, Error, CreateUserInput["user"]>; -export function useCreateUserMutation(params?: { - selection?: ({ - fields?: undefined; - }); -} & Omit; - }; -}, Error, CreateUserInput["user"]>, "mutationFn">): UseMutationResult<{ - createUser: { - user: InferSelectResult; - }; -}, Error, CreateUserInput["user"]>; -export function useCreateUserMutation(params?: { - selection?: SelectionConfig; +export function useCreateUserMutation(params: { + selection: SelectionConfig; } & Omit, "mutationFn">) { const args = buildSelectionArgs(params?.selection); const { @@ -890,7 +751,7 @@ export function useCreateUserMutation(params?: { mutationKey: userMutationKeys.create(), mutationFn: (data: CreateUserInput["user"]) => getClient().user.create({ data, - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(), onSuccess: () => { queryClient.invalidateQueries({ @@ -920,9 +781,6 @@ import { postMutationKeys } from "../mutation-keys"; 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"; -const defaultSelect = { - id: true -} as const; /** * Mutation hook for creating a Post * @@ -948,21 +806,8 @@ export function useCreatePostMutation(params: { post: InferSelectResult; }; }, Error, CreatePostInput["post"]>; -export function useCreatePostMutation(params?: { - selection?: ({ - fields?: undefined; - }); -} & Omit; - }; -}, Error, CreatePostInput["post"]>, "mutationFn">): UseMutationResult<{ - createPost: { - post: InferSelectResult; - }; -}, Error, CreatePostInput["post"]>; -export function useCreatePostMutation(params?: { - selection?: SelectionConfig; +export function useCreatePostMutation(params: { + selection: SelectionConfig; } & Omit, "mutationFn">) { const args = buildSelectionArgs(params?.selection); const { @@ -975,7 +820,7 @@ export function useCreatePostMutation(params?: { mutationKey: postMutationKeys.create(), mutationFn: (data: CreatePostInput["post"]) => getClient().post.create({ data, - select: (args?.select ?? defaultSelect) as PostSelect + select: args.select }).unwrap(), onSuccess: () => { queryClient.invalidateQueries({ @@ -1003,9 +848,6 @@ 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"; -const defaultSelect = { - id: true -} as const; /** * Mutation hook for creating a User * @@ -1031,21 +873,8 @@ export function useCreateUserMutation(params: { user: InferSelectResult; }; }, Error, CreateUserInput["user"]>; -export function useCreateUserMutation(params?: { - selection?: ({ - fields?: undefined; - }); -} & Omit; - }; -}, Error, CreateUserInput["user"]>, "mutationFn">): UseMutationResult<{ - createUser: { - user: InferSelectResult; - }; -}, Error, CreateUserInput["user"]>; -export function useCreateUserMutation(params?: { - selection?: SelectionConfig; +export function useCreateUserMutation(params: { + selection: SelectionConfig; } & Omit, "mutationFn">) { const args = buildSelectionArgs(params?.selection); const { @@ -1057,7 +886,7 @@ export function useCreateUserMutation(params?: { return useMutation({ mutationFn: (data: CreateUserInput["user"]) => getClient().user.create({ data, - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(), onSuccess: () => { queryClient.invalidateQueries({ @@ -1087,9 +916,6 @@ import { userMutationKeys } from "../mutation-keys"; import type { UserSelect, UserWithRelations } from "../../orm/input-types"; import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; export type { UserSelect, UserWithRelations } from "../../orm/input-types"; -const defaultSelect = { - id: true -} as const; /** * Mutation hook for deleting a User * @@ -1119,25 +945,8 @@ export function useDeleteUserMutation(params: { }, Error, { id: string; }>; -export function useDeleteUserMutation(params?: { - selection?: ({ - fields?: undefined; - }); -} & Omit; - }; -}, Error, { - id: string; -}>, "mutationFn">): UseMutationResult<{ - deleteUser: { - user: InferSelectResult; - }; -}, Error, { - id: string; -}>; -export function useDeleteUserMutation(params?: { - selection?: SelectionConfig; +export function useDeleteUserMutation(params: { + selection: SelectionConfig; } & Omit, "mutationFn">) { @@ -1158,7 +967,7 @@ export function useDeleteUserMutation(params?: { where: { id }, - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(), onSuccess: (_, variables) => { queryClient.removeQueries({ @@ -1191,9 +1000,6 @@ import { postMutationKeys } from "../mutation-keys"; import type { PostSelect, PostWithRelations } from "../../orm/input-types"; import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; export type { PostSelect, PostWithRelations } from "../../orm/input-types"; -const defaultSelect = { - id: true -} as const; /** * Mutation hook for deleting a Post * @@ -1223,25 +1029,8 @@ export function useDeletePostMutation(params: { }, Error, { id: string; }>; -export function useDeletePostMutation(params?: { - selection?: ({ - fields?: undefined; - }); -} & Omit; - }; -}, Error, { - id: string; -}>, "mutationFn">): UseMutationResult<{ - deletePost: { - post: InferSelectResult; - }; -}, Error, { - id: string; -}>; -export function useDeletePostMutation(params?: { - selection?: SelectionConfig; +export function useDeletePostMutation(params: { + selection: SelectionConfig; } & Omit, "mutationFn">) { @@ -1262,7 +1051,7 @@ export function useDeletePostMutation(params?: { where: { id }, - select: (args?.select ?? defaultSelect) as PostSelect + select: args.select }).unwrap(), onSuccess: (_, variables) => { queryClient.removeQueries({ @@ -1293,9 +1082,6 @@ 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"; -const defaultSelect = { - id: true -} as const; /** * Mutation hook for deleting a User * @@ -1325,25 +1111,8 @@ export function useDeleteUserMutation(params: { }, Error, { id: string; }>; -export function useDeleteUserMutation(params?: { - selection?: ({ - fields?: undefined; - }); -} & Omit; - }; -}, Error, { - id: string; -}>, "mutationFn">): UseMutationResult<{ - deleteUser: { - user: InferSelectResult; - }; -}, Error, { - id: string; -}>; -export function useDeleteUserMutation(params?: { - selection?: SelectionConfig; +export function useDeleteUserMutation(params: { + selection: SelectionConfig; } & Omit, "mutationFn">) { @@ -1363,7 +1132,7 @@ export function useDeleteUserMutation(params?: { where: { id }, - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(), onSuccess: (_, variables) => { queryClient.removeQueries({ @@ -1396,9 +1165,6 @@ import { userMutationKeys } from "../mutation-keys"; 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"; -const defaultSelect = { - id: true -} as const; /** * Mutation hook for updating a User * @@ -1430,27 +1196,8 @@ export function useUpdateUserMutation(params: { id: string; patch: UserPatch; }>; -export function useUpdateUserMutation(params?: { - selection?: ({ - fields?: undefined; - }); -} & Omit; - }; -}, Error, { - id: string; - patch: UserPatch; -}>, "mutationFn">): UseMutationResult<{ - updateUser: { - user: InferSelectResult; - }; -}, Error, { - id: string; - patch: UserPatch; -}>; -export function useUpdateUserMutation(params?: { - selection?: SelectionConfig; +export function useUpdateUserMutation(params: { + selection: SelectionConfig; } & Omit { queryClient.invalidateQueries({ @@ -1508,9 +1255,6 @@ import { postMutationKeys } from "../mutation-keys"; 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"; -const defaultSelect = { - id: true -} as const; /** * Mutation hook for updating a Post * @@ -1542,27 +1286,8 @@ export function useUpdatePostMutation(params: { id: string; patch: PostPatch; }>; -export function useUpdatePostMutation(params?: { - selection?: ({ - fields?: undefined; - }); -} & Omit; - }; -}, Error, { - id: string; - patch: PostPatch; -}>, "mutationFn">): UseMutationResult<{ - updatePost: { - post: InferSelectResult; - }; -}, Error, { - id: string; - patch: PostPatch; -}>; -export function useUpdatePostMutation(params?: { - selection?: SelectionConfig; +export function useUpdatePostMutation(params: { + selection: SelectionConfig; } & Omit { queryClient.invalidateQueries({ @@ -1618,9 +1343,6 @@ 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"; -const defaultSelect = { - id: true -} as const; /** * Mutation hook for updating a User * @@ -1652,27 +1374,8 @@ export function useUpdateUserMutation(params: { id: string; patch: UserPatch; }>; -export function useUpdateUserMutation(params?: { - selection?: ({ - fields?: undefined; - }); -} & Omit; - }; -}, Error, { - id: string; - patch: UserPatch; -}>, "mutationFn">): UseMutationResult<{ - updateUser: { - user: InferSelectResult; - }; -}, Error, { - id: string; - patch: UserPatch; -}>; -export function useUpdateUserMutation(params?: { - selection?: SelectionConfig; +export function useUpdateUserMutation(params: { + selection: SelectionConfig; } & Omit { queryClient.invalidateQueries({ @@ -1728,9 +1431,6 @@ import { userKeys } from "../query-keys"; 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"; -const defaultSelect = { - id: true -} as const; /** Query key factory - re-exported from query-keys.ts */ export const usersQueryKey = userKeys.list; /** @@ -1757,19 +1457,10 @@ export function useUsersQuery>; }, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; -export function useUsersQuery>; -}>(params?: { - selection?: Omit, "fields"> & { - fields?: undefined; - }; -} & Omit>; -}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; -export function useUsersQuery(params?: { - selection?: ListSelectionConfig; +export function useUsersQuery(params: { + selection: ListSelectionConfig; } & Omit, "queryKey" | "queryFn">) { - const selection = params?.selection; + const selection = params.selection; const args = buildListSelectionArgs(selection); const { selection: _selection, @@ -1780,7 +1471,7 @@ export function useUsersQuery(params?: { queryKey: userKeys.list(args), queryFn: () => getClient().user.findMany({ ...(args ?? {}), - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(), ...queryOptions }); @@ -1805,20 +1496,13 @@ export async function fetchUsersQuery(params: { }): Promise<{ users: ConnectionResult>; }>; -export async function fetchUsersQuery(params?: { - selection?: Omit, "fields"> & { - fields?: undefined; - }; -}): Promise<{ - users: ConnectionResult>; -}>; -export async function fetchUsersQuery(params?: { - selection?: ListSelectionConfig; +export async function fetchUsersQuery(params: { + selection: ListSelectionConfig; }) { const args = buildListSelectionArgs(selection); return getClient().user.findMany({ ...(args ?? {}), - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(); } /** @@ -1834,20 +1518,15 @@ export async function prefetchUsersQuery(queryClient: Quer fields: S; } & Omit, "fields"> & StrictSelect; }): Promise; -export async function prefetchUsersQuery(queryClient: QueryClient, params?: { - selection?: Omit, "fields"> & { - fields?: undefined; - }; -}): Promise; -export async function prefetchUsersQuery(queryClient: QueryClient, params?: { - selection?: ListSelectionConfig; +export async function prefetchUsersQuery(queryClient: QueryClient, params: { + selection: ListSelectionConfig; }): void { const args = buildListSelectionArgs(selection); await queryClient.prefetchQuery({ queryKey: userKeys.list(args), queryFn: () => getClient().user.findMany({ ...(args ?? {}), - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap() }); } @@ -1871,9 +1550,6 @@ import type { PostScope } from "../query-keys"; 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"; -const defaultSelect = { - id: true -} as const; /** Query key factory - re-exported from query-keys.ts */ export const postsQueryKey = postKeys.list; /** @@ -1910,23 +1586,12 @@ export function usePostsQuery, "queryKey" | "queryFn"> & { scope?: PostScope; }): UseQueryResult; -export function usePostsQuery>; -}>(params?: { - selection?: Omit, "fields"> & { - fields?: undefined; - }; -} & Omit>; -}, Error, TData>, "queryKey" | "queryFn"> & { - scope?: PostScope; -}): UseQueryResult; -export function usePostsQuery(params?: { - selection?: ListSelectionConfig; +export function usePostsQuery(params: { + selection: ListSelectionConfig; } & Omit, "queryKey" | "queryFn"> & { scope?: PostScope; }) { - const selection = params?.selection; + const selection = params.selection; const args = buildListSelectionArgs(selection); const { scope, @@ -1938,7 +1603,7 @@ export function usePostsQuery(params?: { queryKey: postKeys.list(args, scope), queryFn: () => getClient().post.findMany({ ...(args ?? {}), - select: (args?.select ?? defaultSelect) as PostSelect + select: args.select }).unwrap(), ...queryOptions }); @@ -1963,20 +1628,13 @@ export async function fetchPostsQuery(params: { }): Promise<{ posts: ConnectionResult>; }>; -export async function fetchPostsQuery(params?: { - selection?: Omit, "fields"> & { - fields?: undefined; - }; -}): Promise<{ - posts: ConnectionResult>; -}>; -export async function fetchPostsQuery(params?: { - selection?: ListSelectionConfig; +export async function fetchPostsQuery(params: { + selection: ListSelectionConfig; }) { const args = buildListSelectionArgs(selection); return getClient().post.findMany({ ...(args ?? {}), - select: (args?.select ?? defaultSelect) as PostSelect + select: args.select }).unwrap(); } /** @@ -1994,15 +1652,8 @@ export async function prefetchPostsQuery(queryClient: Quer } & { scope?: PostScope; }): Promise; -export async function prefetchPostsQuery(queryClient: QueryClient, params?: { - selection?: Omit, "fields"> & { - fields?: undefined; - }; -} & { - scope?: PostScope; -}): Promise; -export async function prefetchPostsQuery(queryClient: QueryClient, params?: { - selection?: ListSelectionConfig; +export async function prefetchPostsQuery(queryClient: QueryClient, params: { + selection: ListSelectionConfig; } & { scope?: PostScope; }): void { @@ -2011,7 +1662,7 @@ export async function prefetchPostsQuery(queryClient: QueryClient, params?: { queryKey: postKeys.list(args, params?.scope), queryFn: () => getClient().post.findMany({ ...(args ?? {}), - select: (args?.select ?? defaultSelect) as PostSelect + select: args.select }).unwrap() }); } @@ -2033,9 +1684,6 @@ 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"; -const defaultSelect = { - id: true -} as const; export const usersQueryKey = (variables?: FindManyArgs) => ["user", "list", variables] as const; /** * Query hook for fetching User list @@ -2061,19 +1709,10 @@ export function useUsersQuery>; }, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; -export function useUsersQuery>; -}>(params?: { - selection?: Omit, "fields"> & { - fields?: undefined; - }; -} & Omit>; -}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; -export function useUsersQuery(params?: { - selection?: ListSelectionConfig; +export function useUsersQuery(params: { + selection: ListSelectionConfig; } & Omit, "queryKey" | "queryFn">) { - const selection = params?.selection; + const selection = params.selection; const args = buildListSelectionArgs(selection); const { selection: _selection, @@ -2084,7 +1723,7 @@ export function useUsersQuery(params?: { queryKey: usersQueryKey(args), queryFn: () => getClient().user.findMany({ ...(args ?? {}), - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(), ...queryOptions }); @@ -2109,20 +1748,13 @@ export async function fetchUsersQuery(params: { }): Promise<{ users: ConnectionResult>; }>; -export async function fetchUsersQuery(params?: { - selection?: Omit, "fields"> & { - fields?: undefined; - }; -}): Promise<{ - users: ConnectionResult>; -}>; -export async function fetchUsersQuery(params?: { - selection?: ListSelectionConfig; +export async function fetchUsersQuery(params: { + selection: ListSelectionConfig; }) { const args = buildListSelectionArgs(selection); return getClient().user.findMany({ ...(args ?? {}), - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(); } /** @@ -2138,20 +1770,15 @@ export async function prefetchUsersQuery(queryClient: Quer fields: S; } & Omit, "fields"> & StrictSelect; }): Promise; -export async function prefetchUsersQuery(queryClient: QueryClient, params?: { - selection?: Omit, "fields"> & { - fields?: undefined; - }; -}): Promise; -export async function prefetchUsersQuery(queryClient: QueryClient, params?: { - selection?: ListSelectionConfig; +export async function prefetchUsersQuery(queryClient: QueryClient, params: { + selection: ListSelectionConfig; }): void { const args = buildListSelectionArgs(selection); await queryClient.prefetchQuery({ queryKey: usersQueryKey(args), queryFn: () => getClient().user.findMany({ ...(args ?? {}), - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap() }); } @@ -2174,9 +1801,6 @@ import { userKeys } from "../query-keys"; import type { UserSelect, UserWithRelations } from "../../orm/input-types"; import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; export type { UserSelect, UserWithRelations } from "../../orm/input-types"; -const defaultSelect = { - id: true -} as const; /** Query key factory - re-exported from query-keys.ts */ export const userQueryKey = userKeys.detail; /** @@ -2200,19 +1824,9 @@ export function useUserQuery | null; }, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; -export function useUserQuery | null; -}>(params: { - id: string; - selection?: { - fields?: undefined; - }; -} & Omit | null; -}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; export function useUserQuery(params: { id: string; - selection?: SelectionConfig; + selection: SelectionConfig; } & Omit, "queryKey" | "queryFn">) { const args = buildSelectionArgs(params.selection); const { @@ -2225,7 +1839,7 @@ export function useUserQuery(params: { queryFn: () => getClient().user.findOne({ id: params.id, ...(args ?? {}), - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(), ...queryOptions }); @@ -2251,21 +1865,13 @@ export async function fetchUserQuery(params: { }>; export async function fetchUserQuery(params: { id: string; - selection?: { - fields?: undefined; - }; -}): Promise<{ - user: InferSelectResult | null; -}>; -export async function fetchUserQuery(params: { - id: string; - selection?: SelectionConfig; + selection: SelectionConfig; }) { const args = buildSelectionArgs(params.selection); return getClient().user.findOne({ id: params.id, ...(args ?? {}), - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(); } /** @@ -2284,13 +1890,7 @@ export async function prefetchUserQuery(queryClient: Query }): Promise; export async function prefetchUserQuery(queryClient: QueryClient, params: { id: string; - selection?: { - fields?: undefined; - }; -}): Promise; -export async function prefetchUserQuery(queryClient: QueryClient, params: { - id: string; - selection?: SelectionConfig; + selection: SelectionConfig; }): void { const args = buildSelectionArgs(params.selection); await queryClient.prefetchQuery({ @@ -2298,7 +1898,7 @@ export async function prefetchUserQuery(queryClient: QueryClient, params: { queryFn: () => getClient().user.findOne({ id: params.id, ...(args ?? {}), - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap() }); } @@ -2322,9 +1922,6 @@ import type { PostScope } from "../query-keys"; import type { PostSelect, PostWithRelations } from "../../orm/input-types"; import type { InferSelectResult, StrictSelect } from "../../orm/select-types"; export type { PostSelect, PostWithRelations } from "../../orm/input-types"; -const defaultSelect = { - id: true -} as const; /** Query key factory - re-exported from query-keys.ts */ export const postQueryKey = postKeys.detail; /** @@ -2358,21 +1955,9 @@ export function usePostQuery, "queryKey" | "queryFn"> & { scope?: PostScope; }): UseQueryResult; -export function usePostQuery | null; -}>(params: { - id: string; - selection?: { - fields?: undefined; - }; -} & Omit | null; -}, Error, TData>, "queryKey" | "queryFn"> & { - scope?: PostScope; -}): UseQueryResult; export function usePostQuery(params: { id: string; - selection?: SelectionConfig; + selection: SelectionConfig; } & Omit, "queryKey" | "queryFn"> & { scope?: PostScope; }) { @@ -2388,7 +1973,7 @@ export function usePostQuery(params: { queryFn: () => getClient().post.findOne({ id: params.id, ...(args ?? {}), - select: (args?.select ?? defaultSelect) as PostSelect + select: args.select }).unwrap(), ...queryOptions }); @@ -2414,21 +1999,13 @@ export async function fetchPostQuery(params: { }>; export async function fetchPostQuery(params: { id: string; - selection?: { - fields?: undefined; - }; -}): Promise<{ - post: InferSelectResult | null; -}>; -export async function fetchPostQuery(params: { - id: string; - selection?: SelectionConfig; + selection: SelectionConfig; }) { const args = buildSelectionArgs(params.selection); return getClient().post.findOne({ id: params.id, ...(args ?? {}), - select: (args?.select ?? defaultSelect) as PostSelect + select: args.select }).unwrap(); } /** @@ -2449,15 +2026,7 @@ export async function prefetchPostQuery(queryClient: Query }): Promise; export async function prefetchPostQuery(queryClient: QueryClient, params: { id: string; - selection?: { - fields?: undefined; - }; -} & { - scope?: PostScope; -}): Promise; -export async function prefetchPostQuery(queryClient: QueryClient, params: { - id: string; - selection?: SelectionConfig; + selection: SelectionConfig; } & { scope?: PostScope; }): void { @@ -2467,7 +2036,7 @@ export async function prefetchPostQuery(queryClient: QueryClient, params: { queryFn: () => getClient().post.findOne({ id: params.id, ...(args ?? {}), - select: (args?.select ?? defaultSelect) as PostSelect + select: args.select }).unwrap() }); } @@ -2489,9 +2058,6 @@ 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"; -const defaultSelect = { - id: true -} as const; export const userQueryKey = (id: string) => ["user", "detail", id] as const; /** * Query hook for fetching a single User @@ -2514,19 +2080,9 @@ export function useUserQuery | null; }, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; -export function useUserQuery | null; -}>(params: { - id: string; - selection?: { - fields?: undefined; - }; -} & Omit | null; -}, Error, TData>, "queryKey" | "queryFn">): UseQueryResult; export function useUserQuery(params: { id: string; - selection?: SelectionConfig; + selection: SelectionConfig; } & Omit, "queryKey" | "queryFn">) { const args = buildSelectionArgs(params.selection); const { @@ -2539,7 +2095,7 @@ export function useUserQuery(params: { queryFn: () => getClient().user.findOne({ id: params.id, ...(args ?? {}), - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(), ...queryOptions }); @@ -2565,21 +2121,13 @@ export async function fetchUserQuery(params: { }>; export async function fetchUserQuery(params: { id: string; - selection?: { - fields?: undefined; - }; -}): Promise<{ - user: InferSelectResult | null; -}>; -export async function fetchUserQuery(params: { - id: string; - selection?: SelectionConfig; + selection: SelectionConfig; }) { const args = buildSelectionArgs(params.selection); return getClient().user.findOne({ id: params.id, ...(args ?? {}), - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap(); } /** @@ -2598,13 +2146,7 @@ export async function prefetchUserQuery(queryClient: Query }): Promise; export async function prefetchUserQuery(queryClient: QueryClient, params: { id: string; - selection?: { - fields?: undefined; - }; -}): Promise; -export async function prefetchUserQuery(queryClient: QueryClient, params: { - id: string; - selection?: SelectionConfig; + selection: SelectionConfig; }): void { const args = buildSelectionArgs(params.selection); await queryClient.prefetchQuery({ @@ -2612,7 +2154,7 @@ export async function prefetchUserQuery(queryClient: QueryClient, params: { queryFn: () => getClient().user.findOne({ id: params.id, ...(args ?? {}), - select: (args?.select ?? defaultSelect) as UserSelect + select: args.select }).unwrap() }); } diff --git a/graphql/codegen/src/core/codegen/custom-mutations.ts b/graphql/codegen/src/core/codegen/custom-mutations.ts index e5ceab809..f8f3f56c4 100644 --- a/graphql/codegen/src/core/codegen/custom-mutations.ts +++ b/graphql/codegen/src/core/codegen/custom-mutations.ts @@ -19,9 +19,7 @@ import type { CleanOperation, TypeRegistry } from '../../types/schema'; -import { asConst } from './babel-ast'; import { - buildDefaultSelectExpr, buildSelectionArgsCall, callExpr, constDecl, @@ -41,7 +39,6 @@ import { selectionConfigType, spreadObj, sRef, - typeofRef, typeRef, useMutationOptionsType, useMutationResultType, @@ -164,11 +161,6 @@ function generateCustomMutationHookInternal( statements.push(createTypeReExport([selectTypeName!], '../../orm/input-types')); } - // Default select - if (hasSelect) { - statements.push(constDecl('defaultSelect', asConst(buildDefaultSelectExpr(payloadTypeName!, typeRegistry)))); - } - // Hook if (hasSelect) { const mutationVarType: t.TSType = hasArgs ? typeRef(varTypeName) : t.tsVoidKeyword(); @@ -204,39 +196,11 @@ function generateCustomMutationHookInternal( ) ); - // Overload 2: without selection.fields - const o2SelectionProp = (() => { - const innerFieldsProp = t.tsPropertySignature( - t.identifier('fields'), - t.tsTypeAnnotation(t.tsUndefinedKeyword()) - ); - innerFieldsProp.optional = true; - const selProp = t.tsPropertySignature( - t.identifier('selection'), - t.tsTypeAnnotation(t.tsParenthesizedType(t.tsTypeLiteral([innerFieldsProp]))) - ); - selProp.optional = true; - return selProp; - })(); - const o2ParamType = t.tsIntersectionType([ - t.tsTypeLiteral([o2SelectionProp]), - useMutationOptionsType(selectedResultType(typeofRef('defaultSelect')), mutationVarType) - ]); - statements.push( - exportDeclareFunction( - hookName, - null, - [createFunctionParam('params', o2ParamType, true)], - useMutationResultType(selectedResultType(typeofRef('defaultSelect')), mutationVarType) - ) - ); - // Implementation const implSelProp = t.tsPropertySignature( t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName!))) ); - implSelProp.optional = true; const implParamType = t.tsIntersectionType([ t.tsTypeLiteral([implSelProp]), omitType( @@ -257,17 +221,7 @@ function generateCustomMutationHookInternal( ) : undefined; - const selectExpr = t.tsAsExpression( - t.parenthesizedExpression( - t.logicalExpression( - '??', - t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), - t.identifier('defaultSelect') - ) - ), - typeRef(selectTypeName!) - ); - const selectObj = t.objectExpression([objectProp('select', selectExpr)]); + const selectObj = t.objectExpression([objectProp('select', t.memberExpression(t.identifier('args'), t.identifier('select')))]); let mutationFnExpr: t.Expression; if (hasArgs) { diff --git a/graphql/codegen/src/core/codegen/custom-queries.ts b/graphql/codegen/src/core/codegen/custom-queries.ts index b94eb1747..cd98d300f 100644 --- a/graphql/codegen/src/core/codegen/custom-queries.ts +++ b/graphql/codegen/src/core/codegen/custom-queries.ts @@ -22,7 +22,6 @@ import type { import { asConst } from './babel-ast'; import { addJSDocComment, - buildDefaultSelectExpr, buildSelectionArgsCall, callExpr, constDecl, @@ -46,7 +45,6 @@ import { selectionConfigType, spreadObj, sRef, - typeofRef, typeRef, useQueryOptionsImplType, useQueryOptionsType, @@ -163,11 +161,6 @@ export function generateCustomQueryHook( statements.push(createTypeReExport([selectTypeName!], '../../orm/input-types')); } - // Default select - if (hasSelect) { - statements.push(constDecl('defaultSelect', asConst(buildDefaultSelectExpr(payloadTypeName!, typeRegistry)))); - } - // Query key if (useCentralizedKeys) { const keyDecl = t.exportNamedDeclaration( @@ -202,18 +195,6 @@ export function generateCustomQueryHook( statements.push(keyDecl); } - // Helper to build select fallback expression - const buildSelectFallback = () => t.tsAsExpression( - t.parenthesizedExpression( - t.logicalExpression( - '??', - t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), - t.identifier('defaultSelect') - ) - ), - typeRef(selectTypeName!) - ); - // Helper to build query key call expression const buildQueryKeyCall = (withVars: boolean) => { if (useCentralizedKeys) { @@ -234,14 +215,7 @@ export function generateCustomQueryHook( ]) ); - // Helper for { fields?: undefined } - const noFieldsType = () => { - const fp = t.tsPropertySignature(t.identifier('fields'), t.tsTypeAnnotation(t.tsUndefinedKeyword())); - fp.optional = true; - return t.tsParenthesizedType(t.tsTypeLiteral([fp])); - }; - - const selectedResultType = (sel: t.TSType) => + const selectedResultType= (sel: t.TSType) => customSelectResultTypeLiteral(operation.name, operation.returnType, payloadTypeName!, sel); // Hook @@ -284,30 +258,6 @@ export function generateCustomQueryHook( ]); statements.push(o1); - // Overload 2: without fields - const o2Props: t.TSPropertySignature[] = []; - if (hasArgs) { - const varProp = t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(typeRef(varTypeName))); - if (!hasRequiredArgs) varProp.optional = true; - o2Props.push(varProp); - } - const selProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(noFieldsType())); - selProp.optional = true; - o2Props.push(selProp); - const o2ParamType = t.tsIntersectionType([ - t.tsTypeLiteral(o2Props), - omitType(typeRef('UseQueryOptions', [selectedResultType(typeofRef('defaultSelect')), typeRef('Error'), typeRef('TData')]), ['queryKey', 'queryFn']) - ]); - const o2Param = createFunctionParam('params', o2ParamType, !hasRequiredArgs); - statements.push( - exportDeclareFunction( - hookName, - createTDataTypeParam(selectedResultType(typeofRef('defaultSelect'))), - [o2Param], - typeRef('UseQueryResult', [typeRef('TData')]) - ) - ); - // Implementation const implProps: t.TSPropertySignature[] = []; if (hasArgs) { @@ -316,7 +266,6 @@ export function generateCustomQueryHook( implProps.push(varProp); } const implSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName!)))); - implSelProp.optional = true; implProps.push(implSelProp); const implParamType = t.tsIntersectionType([ t.tsTypeLiteral(implProps), @@ -346,7 +295,7 @@ export function generateCustomQueryHook( body.push(voidStatement('_selection')); } - const selectObj = t.objectExpression([objectProp('select', buildSelectFallback())]); + const selectObj = t.objectExpression([objectProp('select', t.memberExpression(t.identifier('args'), t.identifier('select')))]); const queryFnArgs = hasArgs ? [hasRequiredArgs ? t.tsNonNullExpression(t.identifier('variables')) : t.identifier('variables'), selectObj] : [selectObj]; @@ -479,25 +428,6 @@ export function generateCustomQueryHook( ]); statements.push(f1Decl); - // Overload 2: without fields - const f2Props: t.TSPropertySignature[] = []; - if (hasArgs) { - const varProp = t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(typeRef(varTypeName))); - if (!hasRequiredArgs) varProp.optional = true; - f2Props.push(varProp); - } - const f2SelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(noFieldsType())); - f2SelProp.optional = true; - f2Props.push(f2SelProp); - statements.push( - exportAsyncDeclareFunction( - fetchFnName, - null, - [createFunctionParam('params', t.tsTypeLiteral(f2Props), !hasRequiredArgs)], - typeRef('Promise', [selectedResultType(typeofRef('defaultSelect'))]) - ) - ); - // Implementation const fImplProps: t.TSPropertySignature[] = []; if (hasArgs) { @@ -506,7 +436,6 @@ export function generateCustomQueryHook( fImplProps.push(varProp); } const fImplSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName!)))); - fImplSelProp.optional = true; fImplProps.push(fImplSelProp); const fBody: t.Statement[] = []; @@ -514,12 +443,12 @@ export function generateCustomQueryHook( fBody.push(constDecl('variables', t.optionalMemberExpression(t.identifier('params'), t.identifier('variables'), false, true))); } fBody.push(buildSelectionArgsCall(selectTypeName!)); - const selectObj = t.objectExpression([objectProp('select', buildSelectFallback())]); + const selectObj = t.objectExpression([objectProp('select', t.memberExpression(t.identifier('args'), t.identifier('select')))]); const fCallArgs = hasArgs ? [hasRequiredArgs ? t.tsNonNullExpression(t.identifier('variables')) : t.identifier('variables'), selectObj] : [selectObj]; fBody.push(t.returnStatement(getClientCustomCallUnwrap('query', operation.name, fCallArgs as t.Expression[]))); - statements.push(exportAsyncFunction(fetchFnName, null, [createFunctionParam('params', t.tsTypeLiteral(fImplProps), !hasRequiredArgs)], fBody)); + statements.push(exportAsyncFunction(fetchFnName, null, [createFunctionParam('params', t.tsTypeLiteral(fImplProps))], fBody)); } else { const fBody: t.Statement[] = []; if (hasArgs) { @@ -587,25 +516,6 @@ export function generateCustomQueryHook( ]); statements.push(p1Decl); - // Overload 2: without fields - const p2Props: t.TSPropertySignature[] = []; - if (hasArgs) { - const varProp = t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(typeRef(varTypeName))); - if (!hasRequiredArgs) varProp.optional = true; - p2Props.push(varProp); - } - const p2SelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(noFieldsType())); - p2SelProp.optional = true; - p2Props.push(p2SelProp); - statements.push( - exportAsyncDeclareFunction( - prefetchFnName, - null, - [createFunctionParam('queryClient', typeRef('QueryClient')), createFunctionParam('params', t.tsTypeLiteral(p2Props), !hasRequiredArgs)], - typeRef('Promise', [t.tsVoidKeyword()]) - ) - ); - // Implementation const pImplProps: t.TSPropertySignature[] = []; if (hasArgs) { @@ -614,7 +524,6 @@ export function generateCustomQueryHook( pImplProps.push(varProp); } const pImplSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName!)))); - pImplSelProp.optional = true; pImplProps.push(pImplSelProp); const pBody: t.Statement[] = []; @@ -622,7 +531,7 @@ export function generateCustomQueryHook( pBody.push(constDecl('variables', t.optionalMemberExpression(t.identifier('params'), t.identifier('variables'), false, true))); } pBody.push(buildSelectionArgsCall(selectTypeName!)); - const selectObj = t.objectExpression([objectProp('select', buildSelectFallback())]); + const selectObj = t.objectExpression([objectProp('select', t.memberExpression(t.identifier('args'), t.identifier('select')))]); const pCallArgs = hasArgs ? [hasRequiredArgs ? t.tsNonNullExpression(t.identifier('variables')) : t.identifier('variables'), selectObj] : [selectObj]; @@ -638,7 +547,7 @@ export function generateCustomQueryHook( exportAsyncFunction( prefetchFnName, null, - [createFunctionParam('queryClient', typeRef('QueryClient')), createFunctionParam('params', t.tsTypeLiteral(pImplProps), !hasRequiredArgs)], + [createFunctionParam('queryClient', typeRef('QueryClient')), createFunctionParam('params', t.tsTypeLiteral(pImplProps))], pBody, t.tsVoidKeyword() ) diff --git a/graphql/codegen/src/core/codegen/hooks-ast.ts b/graphql/codegen/src/core/codegen/hooks-ast.ts index 6b3782f43..0fc7b69ff 100644 --- a/graphql/codegen/src/core/codegen/hooks-ast.ts +++ b/graphql/codegen/src/core/codegen/hooks-ast.ts @@ -6,9 +6,9 @@ */ import * as t from '@babel/types'; -import type { CleanArgument, TypeRegistry } from '../../types/schema'; +import type { CleanArgument } from '../../types/schema'; import { commentBlock, generateCode } from './babel-ast'; -import { getTypeBaseName, scalarToTsType } from './type-resolver'; +import { scalarToTsType } from './type-resolver'; import { getGeneratedFileHeader } from './utils'; // ============================================================================ @@ -197,28 +197,6 @@ export function withFieldsListSelectionType( ]); } -export function withoutFieldsSelectionType(): t.TSTypeLiteral { - return typeLiteralWithProps([{ - name: 'fields', - type: t.tsUndefinedKeyword(), - optional: true - }]); -} - -export function withoutFieldsListSelectionType( - selectTypeName: string, - filterTypeName: string, - orderByTypeName: string -): t.TSIntersectionType { - return t.tsIntersectionType([ - omitType( - listSelectionConfigType(typeRef(selectTypeName), filterTypeName, orderByTypeName), - ['fields'] - ), - withoutFieldsSelectionType() - ]); -} - export function useQueryOptionsType( queryDataType: t.TSType, dataType: t.TSType, @@ -642,33 +620,18 @@ export function getClientCustomCallUnwrap( // Select/args expression builders // ============================================================================ -export function buildSelectFallbackExpr( - argsIdent: string, - defaultSelectIdent: string, - selectTypeName: string -): t.TSAsExpression { - return t.tsAsExpression( - t.parenthesizedExpression( - t.logicalExpression( - '??', - t.optionalMemberExpression( - t.identifier(argsIdent), - t.identifier('select'), - false, - true - ), - t.identifier(defaultSelectIdent) - ) - ), - typeRef(selectTypeName) +export function buildSelectExpr( + argsIdent: string +): t.MemberExpression { + return t.memberExpression( + t.identifier(argsIdent), + t.identifier('select') ); } export function buildFindManyCallExpr( singularName: string, - argsIdent: string, - selectTypeName: string, - defaultSelectIdent: string = 'defaultSelect' + argsIdent: string ): t.CallExpression { const spreadArgs = t.parenthesizedExpression( t.logicalExpression('??', t.identifier(argsIdent), t.objectExpression([])) @@ -678,7 +641,7 @@ export function buildFindManyCallExpr( 'findMany', t.objectExpression([ t.spreadElement(spreadArgs), - objectProp('select', buildSelectFallbackExpr(argsIdent, defaultSelectIdent, selectTypeName)) + objectProp('select', buildSelectExpr(argsIdent)) ]) ); } @@ -687,9 +650,7 @@ export function buildFindOneCallExpr( singularName: string, pkFieldName: string, argsIdent: string, - selectTypeName: string, - paramsIdent: string = 'params', - defaultSelectIdent: string = 'defaultSelect' + paramsIdent: string = 'params' ): t.CallExpression { return getClientCallUnwrap( singularName, @@ -704,7 +665,7 @@ export function buildFindOneCallExpr( t.logicalExpression('??', t.identifier(argsIdent), t.objectExpression([])) ) ), - objectProp('select', buildSelectFallbackExpr(argsIdent, defaultSelectIdent, selectTypeName)) + objectProp('select', buildSelectExpr(argsIdent)) ]) ); } @@ -738,13 +699,6 @@ export function scopeTypeLiteral(scopeTypeName: string): t.TSTypeLiteral { // Type conversion helpers (GraphQL -> AST) // ============================================================================ -const NON_SELECT_TYPES_AST = new Set([ - 'String', 'Int', 'Float', 'Boolean', 'ID', - 'BigFloat', 'BigInt', 'Cursor', 'Date', 'Datetime', - 'JSON', 'UUID', 'Uuid', 'Time', - 'Query', 'Mutation' -]); - export function wrapInferSelectResultType( typeRefNode: CleanArgument['type'], payloadTypeName: string, @@ -788,46 +742,6 @@ export function typeRefToTsTypeAST( return typeRef(typeRefNode.name ?? 'unknown'); } -export function buildDefaultSelectExpr( - typeName: string, - typeRegistry: TypeRegistry, - depth: number = 0 -): t.ObjectExpression { - const resolved = typeRegistry.get(typeName); - const fields = resolved?.fields ?? []; - - if (depth > 3 || fields.length === 0) { - const fieldName = fields.length > 0 ? fields[0].name : 'id'; - return t.objectExpression([objectProp(fieldName, t.booleanLiteral(true))]); - } - - const idLike = fields.find((f) => f.name === 'id' || f.name === 'nodeId'); - if (idLike) return t.objectExpression([objectProp(idLike.name, t.booleanLiteral(true))]); - - const scalarField = fields.find((f) => { - const baseName = getTypeBaseName(f.type); - if (!baseName) return false; - if (NON_SELECT_TYPES_AST.has(baseName)) return true; - return typeRegistry.get(baseName)?.kind === 'ENUM'; - }); - if (scalarField) return t.objectExpression([objectProp(scalarField.name, t.booleanLiteral(true))]); - - const first = fields[0]; - const firstBase = getTypeBaseName(first.type); - if ( - !firstBase || - NON_SELECT_TYPES_AST.has(firstBase) || - typeRegistry.get(firstBase)?.kind === 'ENUM' - ) { - return t.objectExpression([objectProp(first.name, t.booleanLiteral(true))]); - } - - const nested = buildDefaultSelectExpr(firstBase, typeRegistry, depth + 1); - return t.objectExpression([ - objectProp(first.name, t.objectExpression([objectProp('select', nested)])) - ]); -} - export function buildSelectionArgsCall( selectTypeName: string ): t.VariableDeclaration { diff --git a/graphql/codegen/src/core/codegen/mutations.ts b/graphql/codegen/src/core/codegen/mutations.ts index 1edbbe07a..3814f15f3 100644 --- a/graphql/codegen/src/core/codegen/mutations.ts +++ b/graphql/codegen/src/core/codegen/mutations.ts @@ -10,7 +10,6 @@ import * as t from '@babel/types'; import type { CleanTable } from '../../types/schema'; -import { asConst } from './babel-ast'; import { addJSDocComment, buildSelectionArgsCall, @@ -33,7 +32,6 @@ import { shorthandProp, spreadObj, sRef, - typeofRef, typeRef, typeLiteralWithProps, useMutationOptionsType, @@ -44,7 +42,6 @@ import { getCreateMutationFileName, getCreateMutationHookName, getCreateMutationName, - getDefaultSelectFieldName, getDeleteMutationFileName, getDeleteMutationHookName, getDeleteMutationName, @@ -82,19 +79,6 @@ function buildMutationResultType( }]); } -function buildSelectFallback(selectTypeName: string): t.TSAsExpression { - return t.tsAsExpression( - t.parenthesizedExpression( - t.logicalExpression( - '??', - t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), - t.identifier('defaultSelect') - ) - ), - typeRef(selectTypeName) - ); -} - function buildFieldsSelectionType(s: t.TSType, selectTypeName: string): t.TSParenthesizedType { return t.tsParenthesizedType( t.tsIntersectionType([ @@ -104,12 +88,6 @@ function buildFieldsSelectionType(s: t.TSType, selectTypeName: string): t.TSPare ); } -function buildNoFieldsType(): t.TSParenthesizedType { - const fp = t.tsPropertySignature(t.identifier('fields'), t.tsTypeAnnotation(t.tsUndefinedKeyword())); - fp.optional = true; - return t.tsParenthesizedType(t.tsTypeLiteral([fp])); -} - export function generateCreateMutationHook( table: CleanTable, options: MutationGeneratorOptions = {} @@ -129,7 +107,6 @@ export function generateCreateMutationHook( const selectTypeName = `${typeName}Select`; const relationTypeName = `${typeName}WithRelations`; const createInputTypeName = `Create${typeName}Input`; - const defaultFieldName = getDefaultSelectFieldName(table); const statements: t.Statement[] = []; @@ -151,9 +128,6 @@ export function generateCreateMutationHook( // Re-exports statements.push(createTypeReExport([selectTypeName, relationTypeName, createInputTypeName], '../../orm/input-types')); - // Default select - statements.push(constDecl('defaultSelect', asConst(t.objectExpression([objectProp(defaultFieldName, t.booleanLiteral(true))])))); - // Variable type: CreateTypeName['singularName'] const createVarType = t.tsIndexedAccessType( typeRef(createInputTypeName), @@ -189,25 +163,8 @@ export function generateCreateMutationHook( ]); statements.push(o1); - // Overload 2: without fields - const o2SelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(buildNoFieldsType())); - o2SelProp.optional = true; - const o2ParamType = t.tsIntersectionType([ - t.tsTypeLiteral([o2SelProp]), - useMutationOptionsType(resultType(typeofRef('defaultSelect')), createVarType) - ]); - statements.push( - exportDeclareFunction( - hookName, - null, - [createFunctionParam('params', o2ParamType, true)], - useMutationResultType(resultType(typeofRef('defaultSelect')), createVarType) - ) - ); - // Implementation const implSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName)))); - implSelProp.optional = true; const implParamType = t.tsIntersectionType([ t.tsTypeLiteral([implSelProp]), omitType(typeRef('UseMutationOptions', [t.tsAnyKeyword(), typeRef('Error'), createVarType]), ['mutationFn']) @@ -229,7 +186,7 @@ export function generateCreateMutationHook( [dataParam], getClientCallUnwrap(singularName, 'create', t.objectExpression([ shorthandProp('data'), - objectProp('select', buildSelectFallback(selectTypeName)) + objectProp('select', t.memberExpression(t.identifier('args'), t.identifier('select'))) ])) ); @@ -261,7 +218,7 @@ export function generateCreateMutationHook( ) ); - statements.push(exportFunction(hookName, null, [createFunctionParam('params', implParamType, true)], body)); + statements.push(exportFunction(hookName, null, [createFunctionParam('params', implParamType)], body)); return { fileName: getCreateMutationFileName(table), @@ -316,9 +273,6 @@ export function generateUpdateMutationHook( // Re-exports statements.push(createTypeReExport([selectTypeName, relationTypeName, patchTypeName], '../../orm/input-types')); - // Default select - statements.push(constDecl('defaultSelect', asConst(t.objectExpression([objectProp(pkField.name, t.booleanLiteral(true))])))); - // Variable type: { pkField: type; patch: PatchType } const updateVarType = t.tsTypeLiteral([ t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkTsType)), @@ -354,25 +308,8 @@ export function generateUpdateMutationHook( ]); statements.push(o1); - // Overload 2: without fields - const o2SelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(buildNoFieldsType())); - o2SelProp.optional = true; - const o2ParamType = t.tsIntersectionType([ - t.tsTypeLiteral([o2SelProp]), - useMutationOptionsType(resultType(typeofRef('defaultSelect')), updateVarType) - ]); - statements.push( - exportDeclareFunction( - hookName, - null, - [createFunctionParam('params', o2ParamType, true)], - useMutationResultType(resultType(typeofRef('defaultSelect')), updateVarType) - ) - ); - // Implementation const implSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName)))); - implSelProp.optional = true; const implParamType = t.tsIntersectionType([ t.tsTypeLiteral([implSelProp]), omitType(typeRef('UseMutationOptions', [t.tsAnyKeyword(), typeRef('Error'), updateVarType]), ['mutationFn']) @@ -400,7 +337,7 @@ export function generateUpdateMutationHook( getClientCallUnwrap(singularName, 'update', t.objectExpression([ objectProp('where', t.objectExpression([shorthandProp(pkField.name)])), objectProp('data', t.identifier('patch')), - objectProp('select', buildSelectFallback(selectTypeName)) + objectProp('select', t.memberExpression(t.identifier('args'), t.identifier('select'))) ])) ); @@ -445,7 +382,7 @@ export function generateUpdateMutationHook( ) ); - statements.push(exportFunction(hookName, null, [createFunctionParam('params', implParamType, true)], body)); + statements.push(exportFunction(hookName, null, [createFunctionParam('params', implParamType)], body)); return { fileName: getUpdateMutationFileName(table), @@ -499,9 +436,6 @@ export function generateDeleteMutationHook( // Re-exports statements.push(createTypeReExport([selectTypeName, relationTypeName], '../../orm/input-types')); - // Default select - statements.push(constDecl('defaultSelect', asConst(t.objectExpression([objectProp(pkField.name, t.booleanLiteral(true))])))); - // Variable type: { pkField: type } const deleteVarType = t.tsTypeLiteral([ t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkTsType)) @@ -536,25 +470,8 @@ export function generateDeleteMutationHook( ]); statements.push(o1); - // Overload 2: without fields - const o2SelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(buildNoFieldsType())); - o2SelProp.optional = true; - const o2ParamType = t.tsIntersectionType([ - t.tsTypeLiteral([o2SelProp]), - useMutationOptionsType(resultType(typeofRef('defaultSelect')), deleteVarType) - ]); - statements.push( - exportDeclareFunction( - hookName, - null, - [createFunctionParam('params', o2ParamType, true)], - useMutationResultType(resultType(typeofRef('defaultSelect')), deleteVarType) - ) - ); - // Implementation const implSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName)))); - implSelProp.optional = true; const implParamType = t.tsIntersectionType([ t.tsTypeLiteral([implSelProp]), omitType(typeRef('UseMutationOptions', [t.tsAnyKeyword(), typeRef('Error'), deleteVarType]), ['mutationFn']) @@ -578,7 +495,7 @@ export function generateDeleteMutationHook( [destructParam], getClientCallUnwrap(singularName, 'delete', t.objectExpression([ objectProp('where', t.objectExpression([shorthandProp(pkField.name)])), - objectProp('select', buildSelectFallback(selectTypeName)) + objectProp('select', t.memberExpression(t.identifier('args'), t.identifier('select'))) ])) ); @@ -621,7 +538,7 @@ export function generateDeleteMutationHook( ) ); - statements.push(exportFunction(hookName, null, [createFunctionParam('params', implParamType, true)], body)); + statements.push(exportFunction(hookName, null, [createFunctionParam('params', implParamType)], body)); return { fileName: getDeleteMutationFileName(table), 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 5fbcf5f26..beec9d54e 100644 --- a/graphql/codegen/src/core/codegen/orm/custom-ops-generator.ts +++ b/graphql/codegen/src/core/codegen/orm/custom-ops-generator.ts @@ -6,8 +6,8 @@ */ import * as t from '@babel/types'; -import type { CleanArgument, CleanOperation, TypeRegistry } from '../../../types/schema'; -import { asConst, generateCode } from '../babel-ast'; +import type { CleanArgument, CleanOperation } from '../../../types/schema'; +import { generateCode } from '../babel-ast'; import { NON_SELECT_TYPES, getSelectTypeName } from '../select-helpers'; import { getTypeBaseName, @@ -173,77 +173,9 @@ function buildSelectedResultTsType( ); } -function buildDefaultSelectExpression( - typeName: string, - typeRegistry: TypeRegistry, - depth: number = 0 -): t.Expression { - const resolved = typeRegistry.get(typeName); - const fields = resolved?.fields ?? []; - - if (depth > 3 || fields.length === 0) { - // Use first field if available, otherwise fallback to 'id' - const fallbackName = fields.length > 0 ? fields[0].name : 'id'; - return t.objectExpression([t.objectProperty(t.identifier(fallbackName), t.booleanLiteral(true))]); - } - - // Prefer id-like fields - const idLike = fields.find((f) => f.name === 'id' || f.name === 'nodeId'); - if (idLike) { - return t.objectExpression([ - t.objectProperty(t.identifier(idLike.name), t.booleanLiteral(true)) - ]); - } - - // Prefer scalar/enum fields - const scalarField = fields.find((f) => { - const baseName = getTypeBaseName(f.type); - if (!baseName) return false; - if (NON_SELECT_TYPES.has(baseName)) return true; - const baseResolved = typeRegistry.get(baseName); - return baseResolved?.kind === 'ENUM'; - }); - - if (scalarField) { - return t.objectExpression([ - t.objectProperty(t.identifier(scalarField.name), t.booleanLiteral(true)) - ]); - } - - // Fallback: first field (ensure valid selection for object fields) - const first = fields[0]; - - const firstBaseName = getTypeBaseName(first.type); - if (!firstBaseName || NON_SELECT_TYPES.has(firstBaseName)) { - return t.objectExpression([ - t.objectProperty(t.identifier(first.name), t.booleanLiteral(true)) - ]); - } - - const nestedResolved = typeRegistry.get(firstBaseName); - if (nestedResolved?.kind === 'ENUM') { - return t.objectExpression([ - t.objectProperty(t.identifier(first.name), t.booleanLiteral(true)) - ]); - } - - return t.objectExpression([ - t.objectProperty( - t.identifier(first.name), - t.objectExpression([ - t.objectProperty( - t.identifier('select'), - buildDefaultSelectExpression(firstBaseName, typeRegistry, depth + 1) - ) - ]) - ) - ]); -} - function buildOperationMethod( op: CleanOperation, - operationType: 'query' | 'mutation', - defaultSelectIdent?: t.Identifier + operationType: 'query' | 'mutation' ): t.ObjectProperty { const hasArgs = op.args.length > 0; const varTypeName = `${ucFirst(op.name)}Variables`; @@ -265,7 +197,7 @@ function buildOperationMethod( } const optionsParam = t.identifier('options'); - optionsParam.optional = true; + optionsParam.optional = !selectTypeName; if (selectTypeName) { const selectProp = t.tsPropertySignature( t.identifier('select'), @@ -306,12 +238,8 @@ function buildOperationMethod( params.push(optionsParam); // Build the QueryBuilder call - const selectExpr = defaultSelectIdent - ? t.logicalExpression( - '??', - t.optionalMemberExpression(t.identifier('options'), t.identifier('select'), false, true), - defaultSelectIdent - ) + 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) @@ -375,12 +303,9 @@ function buildOperationMethod( // Add type parameters to arrow function if we have a select type if (selectTypeName) { - const defaultType = defaultSelectIdent - ? t.tsTypeQuery(defaultSelectIdent) - : null; const typeParam = t.tsTypeParameter( t.tsTypeReference(t.identifier(selectTypeName)), - defaultType, + null, 'S' ); arrowFunc.typeParameters = t.tsTypeParameterDeclaration([typeParam]); @@ -393,8 +318,7 @@ function buildOperationMethod( * Generate the query/index.ts file for custom query operations */ export function generateCustomQueryOpsFile( - operations: CleanOperation[], - typeRegistry: TypeRegistry + operations: CleanOperation[] ): GeneratedCustomOpsFile { const statements: t.Statement[] = []; @@ -421,28 +345,9 @@ export function generateCustomQueryOpsFile( if (varInterface) statements.push(varInterface); } - // Default selects (avoid invalid documents when select is omitted) - const defaultSelectIdentsByOpName = new Map(); - for (const op of operations) { - const selectTypeName = getSelectTypeName(op.returnType); - const payloadTypeName = getTypeBaseName(op.returnType); - if (!selectTypeName || !payloadTypeName) continue; - - const ident = t.identifier(`${op.name}DefaultSelect`); - defaultSelectIdentsByOpName.set(op.name, ident); - statements.push( - t.variableDeclaration('const', [ - t.variableDeclarator( - ident, - asConst(buildDefaultSelectExpression(payloadTypeName, typeRegistry)) - ) - ]) - ); - } - // Generate factory function const operationProperties = operations.map((op) => - buildOperationMethod(op, 'query', defaultSelectIdentsByOpName.get(op.name)) + buildOperationMethod(op, 'query') ); const returnObj = t.objectExpression(operationProperties); @@ -471,8 +376,7 @@ export function generateCustomQueryOpsFile( * Generate the mutation/index.ts file for custom mutation operations */ export function generateCustomMutationOpsFile( - operations: CleanOperation[], - typeRegistry: TypeRegistry + operations: CleanOperation[] ): GeneratedCustomOpsFile { const statements: t.Statement[] = []; @@ -499,28 +403,9 @@ export function generateCustomMutationOpsFile( if (varInterface) statements.push(varInterface); } - // Default selects (avoid invalid documents when select is omitted) - const defaultSelectIdentsByOpName = new Map(); - for (const op of operations) { - const selectTypeName = getSelectTypeName(op.returnType); - const payloadTypeName = getTypeBaseName(op.returnType); - if (!selectTypeName || !payloadTypeName) continue; - - const ident = t.identifier(`${op.name}DefaultSelect`); - defaultSelectIdentsByOpName.set(op.name, ident); - statements.push( - t.variableDeclaration('const', [ - t.variableDeclarator( - ident, - asConst(buildDefaultSelectExpression(payloadTypeName, typeRegistry)) - ) - ]) - ); - } - // Generate factory function const operationProperties = operations.map((op) => - buildOperationMethod(op, 'mutation', defaultSelectIdentsByOpName.get(op.name)) + buildOperationMethod(op, 'mutation') ); const returnObj = t.objectExpression(operationProperties); diff --git a/graphql/codegen/src/core/codegen/orm/index.ts b/graphql/codegen/src/core/codegen/orm/index.ts index afeff9380..3ff30cb62 100644 --- a/graphql/codegen/src/core/codegen/orm/index.ts +++ b/graphql/codegen/src/core/codegen/orm/index.ts @@ -128,16 +128,14 @@ export function generateOrm(options: GenerateOrmOptions): GenerateOrmResult { // 5. Generate custom operations (if any) if (hasCustomQueries && customOperations?.queries) { const queryOpsFile = generateCustomQueryOpsFile( - customOperations.queries, - typeRegistry ?? new Map() + customOperations.queries ); files.push({ path: queryOpsFile.fileName, content: queryOpsFile.content }); } if (hasCustomMutations && customOperations?.mutations) { const mutationOpsFile = generateCustomMutationOpsFile( - customOperations.mutations, - typeRegistry ?? new Map() + customOperations.mutations ); files.push({ path: mutationOpsFile.fileName, content: mutationOpsFile.content }); } diff --git a/graphql/codegen/src/core/codegen/orm/model-generator.ts b/graphql/codegen/src/core/codegen/orm/model-generator.ts index 67f8a29a5..a9935ef18 100644 --- a/graphql/codegen/src/core/codegen/orm/model-generator.ts +++ b/graphql/codegen/src/core/codegen/orm/model-generator.ts @@ -9,7 +9,6 @@ import * as t from '@babel/types'; import type { CleanTable } from '../../../types/schema'; import { asConst, generateCode } from '../babel-ast'; import { - getDefaultSelectFieldName, getFilterTypeName, getGeneratedFileHeader, getOrderByTypeName, @@ -130,16 +129,6 @@ function requiredSelectProp(): t.TSPropertySignature { return prop; } -/** Build an optional `select?: undefined` prop to forbid select in fallback overloads */ -function optionalUndefinedSelectProp(): t.TSPropertySignature { - const prop = t.tsPropertySignature( - t.identifier('select'), - t.tsTypeAnnotation(t.tsUndefinedKeyword()) - ); - prop.optional = true; - return prop; -} - /** Build `StrictSelect` type reference for overload intersections */ function strictSelectGuard(selectTypeName: string): t.TSType { return t.tsTypeReference( @@ -151,20 +140,6 @@ function strictSelectGuard(selectTypeName: string): t.TSType { ); } -/** Build `Omit & { select?: undefined }` for fallback overloads */ -function withoutSelect(argsType: t.TSType): t.TSType { - return t.tsIntersectionType([ - t.tsTypeReference( - t.identifier('Omit'), - t.tsTypeParameterInstantiation([ - argsType, - t.tsLiteralType(t.stringLiteral('select')) - ]) - ), - t.tsTypeLiteral([optionalUndefinedSelectProp()]) - ]); -} - export function generateModelFile( table: CleanTable, _useSharedTypes: boolean @@ -186,10 +161,7 @@ export function generateModelFile( const pkFields = getPrimaryKeyInfo(table); const pkField = pkFields[0]; - const defaultSelectIdent = t.identifier('defaultSelect'); - const defaultSelectFieldName = getDefaultSelectFieldName(table); - - const pluralQueryName = table.query?.all ?? pluralName; + const pluralQueryName= table.query?.all ?? pluralName; const createMutationName = table.query?.create ?? `create${typeName}`; const updateMutationName = table.query?.update; const deleteMutationName = table.query?.delete; @@ -211,20 +183,6 @@ export function generateModelFile( ], true)); statements.push(createImportDeclaration('../input-types', ['connectionFieldsMap'])); - // Default select (ensures valid GraphQL selection + sound TS return types) - statements.push( - t.variableDeclaration('const', [ - t.variableDeclarator( - defaultSelectIdent, - asConst( - t.objectExpression([ - t.objectProperty(t.identifier(defaultSelectFieldName), t.booleanLiteral(true)) - ]) - ) - ) - ]) - ); - const classBody: t.ClassBody['body'] = []; // Constructor @@ -236,7 +194,6 @@ export function generateModelFile( // Reusable type reference factories const sRef = () => t.tsTypeReference(t.identifier('S')); - const defaultRef = () => t.tsTypeQuery(defaultSelectIdent); const selectRef = () => t.tsTypeReference(t.identifier(selectTypeName)); const pkTsType = () => tsTypeFromPrimitive(pkField.tsType); @@ -275,19 +232,10 @@ export function generateModelFile( ); classBody.push(createDeclareMethod('findMany', createTypeParam(selectTypeName), [o1Param], retType(sRef()))); - // Overload 2: without select (default) - const o2Param = t.identifier('args'); - o2Param.optional = true; - o2Param.typeAnnotation = t.tsTypeAnnotation(withoutSelect(argsType(selectRef()))); - classBody.push(createDeclareMethod('findMany', null, [o2Param], retType(defaultRef()))); - // Implementation const implParam = t.identifier('args'); - implParam.optional = true; implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef())); - const selectExpr = t.logicalExpression('??', - t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), - defaultSelectIdent); + const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select')); const bodyArgs = [ t.stringLiteral(typeName), t.stringLiteral(pluralQueryName), @@ -348,19 +296,10 @@ export function generateModelFile( ); classBody.push(createDeclareMethod('findFirst', createTypeParam(selectTypeName), [o1Param], retType(sRef()))); - // Overload 2: without select (default) - const o2Param = t.identifier('args'); - o2Param.optional = true; - o2Param.typeAnnotation = t.tsTypeAnnotation(withoutSelect(argsType(selectRef()))); - classBody.push(createDeclareMethod('findFirst', null, [o2Param], retType(defaultRef()))); - // Implementation const implParam = t.identifier('args'); - implParam.optional = true; implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef())); - const selectExpr = t.logicalExpression('??', - t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true), - defaultSelectIdent); + const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select')); const bodyArgs = [ t.stringLiteral(typeName), t.stringLiteral(pluralQueryName), @@ -413,13 +352,6 @@ export function generateModelFile( ); classBody.push(createDeclareMethod('findOne', createTypeParam(selectTypeName), [o1Param], retType(sRef()))); - // Overload 2: without select (default) - const o2Param = t.identifier('args'); - o2Param.typeAnnotation = t.tsTypeAnnotation( - t.tsTypeLiteral([pkProp()]) - ); - classBody.push(createDeclareMethod('findOne', null, [o2Param], retType(defaultRef()))); - // Implementation const implParam = t.identifier('args'); implParam.typeAnnotation = t.tsTypeAnnotation( @@ -430,14 +362,11 @@ export function generateModelFile( t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(selectTypeName))) ); - prop.optional = true; return prop; })() ]) ); - const selectExpr = t.logicalExpression('??', - t.memberExpression(t.identifier('args'), t.identifier('select')), - defaultSelectIdent); + const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select')); const bodyArgs = [ t.stringLiteral(typeName), t.stringLiteral(singleQueryName), @@ -488,17 +417,10 @@ export function generateModelFile( ); classBody.push(createDeclareMethod('create', createTypeParam(selectTypeName), [o1Param], retType(sRef()))); - // Overload 2: without select (default) - const o2Param = t.identifier('args'); - o2Param.typeAnnotation = t.tsTypeAnnotation(withoutSelect(argsType(selectRef()))); - classBody.push(createDeclareMethod('create', null, [o2Param], retType(defaultRef()))); - // Implementation const implParam = t.identifier('args'); implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef())); - const selectExpr = t.logicalExpression('??', - t.memberExpression(t.identifier('args'), t.identifier('select')), - defaultSelectIdent); + const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select')); const bodyArgs = [ t.stringLiteral(typeName), t.stringLiteral(createMutationName), @@ -554,17 +476,10 @@ export function generateModelFile( ); classBody.push(createDeclareMethod('update', createTypeParam(selectTypeName), [o1Param], retType(sRef()))); - // Overload 2: without select (default) - const o2Param = t.identifier('args'); - o2Param.typeAnnotation = t.tsTypeAnnotation(withoutSelect(argsType(selectRef()))); - classBody.push(createDeclareMethod('update', null, [o2Param], retType(defaultRef()))); - // Implementation const implParam = t.identifier('args'); implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef())); - const selectExpr = t.logicalExpression('??', - t.memberExpression(t.identifier('args'), t.identifier('select')), - defaultSelectIdent); + const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select')); const bodyArgs = [ t.stringLiteral(typeName), t.stringLiteral(updateMutationName), @@ -623,17 +538,10 @@ export function generateModelFile( ); classBody.push(createDeclareMethod('delete', createTypeParam(selectTypeName), [o1Param], retType(sRef()))); - // Overload 2: without select (default) - const o2Param = t.identifier('args'); - o2Param.typeAnnotation = t.tsTypeAnnotation(withoutSelect(argsType(selectRef()))); - classBody.push(createDeclareMethod('delete', null, [o2Param], retType(defaultRef()))); - // Implementation const implParam = t.identifier('args'); implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef())); - const selectExpr = t.logicalExpression('??', - t.memberExpression(t.identifier('args'), t.identifier('select')), - defaultSelectIdent); + const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select')); const bodyArgs = [ t.stringLiteral(typeName), t.stringLiteral(deleteMutationName), diff --git a/graphql/codegen/src/core/codegen/queries.ts b/graphql/codegen/src/core/codegen/queries.ts index 38e4e5395..a33d52a6d 100644 --- a/graphql/codegen/src/core/codegen/queries.ts +++ b/graphql/codegen/src/core/codegen/queries.ts @@ -16,7 +16,6 @@ import { buildFindOneCallExpr, buildListSelectionArgsCall, buildSelectionArgsCall, - buildSelectFallbackExpr, callExpr, connectionResultType, constDecl, @@ -24,7 +23,6 @@ import { createImportDeclaration, createSAndTDataTypeParams, createSTypeParam, - createTDataTypeParam, createTypeReExport, destructureParamsWithSelection, destructureParamsWithSelectionAndScope, @@ -44,20 +42,16 @@ import { singleQueryResultType, spreadObj, sRef, - typeofRef, typeRef, typeLiteralWithProps, useQueryOptionsType, useQueryOptionsImplType, voidStatement, withFieldsListSelectionType, - withFieldsSelectionType, - withoutFieldsListSelectionType, - withoutFieldsSelectionType + withFieldsSelectionType } from './hooks-ast'; import { getAllRowsQueryName, - getDefaultSelectFieldName, getFilterTypeName, getListQueryFileName, getListQueryHookName, @@ -101,7 +95,6 @@ export function generateListQueryHook( const scopeTypeName = `${typeName}Scope`; const selectTypeName = `${typeName}Select`; const relationTypeName = `${typeName}WithRelations`; - const defaultFieldName = getDefaultSelectFieldName(table); const listResultTypeAST = (sel: t.TSType) => listQueryResultType(queryName, relationTypeName, sel); @@ -129,9 +122,6 @@ export function generateListQueryHook( // Re-exports statements.push(createTypeReExport([selectTypeName, relationTypeName, filterTypeName, orderByTypeName], '../../orm/input-types')); - // Default select - statements.push(constDecl('defaultSelect', asConst(t.objectExpression([objectProp(defaultFieldName, t.booleanLiteral(true))])))); - // Query key if (useCentralizedKeys) { const keyDecl = t.exportNamedDeclaration( @@ -167,7 +157,7 @@ export function generateListQueryHook( // Helper for findMany queryFn const buildFindManyFn = () => t.arrowFunctionExpression( [], - buildFindManyCallExpr(singularName, 'args', selectTypeName) + buildFindManyCallExpr(singularName, 'args') ); // Options type builder with optional scope @@ -229,32 +219,12 @@ export function generateListQueryHook( addJSDocComment(o1, docLines); statements.push(o1); - // Overload 2: without fields - const o2SelProp = t.tsPropertySignature( - t.identifier('selection'), - t.tsTypeAnnotation(withoutFieldsListSelectionType(selectTypeName, filterTypeName, orderByTypeName)) - ); - o2SelProp.optional = true; - const o2ParamType = t.tsIntersectionType([ - t.tsTypeLiteral([o2SelProp]), - buildOptionsType(listResultTypeAST(typeofRef('defaultSelect')), typeRef('TData')) - ]); - statements.push( - exportDeclareFunction( - hookName, - createTDataTypeParam(listResultTypeAST(typeofRef('defaultSelect'))), - [createFunctionParam('params', o2ParamType, true)], - typeRef('UseQueryResult', [typeRef('TData')]) - ) - ); - // Implementation const implSelProp = t.tsPropertySignature( t.identifier('selection'), t.tsTypeAnnotation(listSelectionConfigType(typeRef(selectTypeName), filterTypeName, orderByTypeName)) ); - implSelProp.optional = true; - const implOptionsType = (() => { + const implOptionsType= (() => { const base = useQueryOptionsImplType(); if (hasRelationships && useCentralizedKeys) { return t.tsIntersectionType([base, scopeTypeLiteral(scopeTypeName)]); @@ -267,7 +237,7 @@ export function generateListQueryHook( ]); const body: t.Statement[] = []; - body.push(constDecl('selection', t.optionalMemberExpression(t.identifier('params'), t.identifier('selection'), false, true))); + body.push(constDecl('selection', t.memberExpression(t.identifier('params'), t.identifier('selection')))); body.push(buildListSelectionArgsCall(selectTypeName, filterTypeName, orderByTypeName)); if (hasRelationships && useCentralizedKeys) { @@ -288,7 +258,7 @@ export function generateListQueryHook( )); } - statements.push(exportFunction(hookName, null, [createFunctionParam('params', implParamType, true)], body)); + statements.push(exportFunction(hookName, null, [createFunctionParam('params', implParamType)], body)); } // Fetch function @@ -322,31 +292,15 @@ export function generateListQueryHook( ]); statements.push(f1Decl); - // Overload 2: without fields - const f2SelProp = t.tsPropertySignature( - t.identifier('selection'), - t.tsTypeAnnotation(withoutFieldsListSelectionType(selectTypeName, filterTypeName, orderByTypeName)) - ); - f2SelProp.optional = true; - statements.push( - exportAsyncDeclareFunction( - fetchFnName, - null, - [createFunctionParam('params', t.tsTypeLiteral([f2SelProp]), true)], - typeRef('Promise', [listResultTypeAST(typeofRef('defaultSelect'))]) - ) - ); - // Implementation const fImplSelProp = t.tsPropertySignature( t.identifier('selection'), t.tsTypeAnnotation(listSelectionConfigType(typeRef(selectTypeName), filterTypeName, orderByTypeName)) ); - fImplSelProp.optional = true; const fBody: t.Statement[] = []; fBody.push(buildListSelectionArgsCall(selectTypeName, filterTypeName, orderByTypeName)); - fBody.push(t.returnStatement(buildFindManyCallExpr(singularName, 'args', selectTypeName))); - statements.push(exportAsyncFunction(fetchFnName, null, [createFunctionParam('params', t.tsTypeLiteral([fImplSelProp]), true)], fBody)); + fBody.push(t.returnStatement(buildFindManyCallExpr(singularName, 'args'))); + statements.push(exportAsyncFunction(fetchFnName, null, [createFunctionParam('params', t.tsTypeLiteral([fImplSelProp]))], fBody)); } // Prefetch function @@ -379,30 +333,11 @@ export function generateListQueryHook( ]); statements.push(p1Decl); - // Overload 2: without fields - const p2SelProp = t.tsPropertySignature( - t.identifier('selection'), - t.tsTypeAnnotation(withoutFieldsListSelectionType(selectTypeName, filterTypeName, orderByTypeName)) - ); - p2SelProp.optional = true; - const p2ParamType = hasRelationships && useCentralizedKeys - ? t.tsIntersectionType([t.tsTypeLiteral([p2SelProp]), scopeTypeLiteral(scopeTypeName)]) - : t.tsTypeLiteral([p2SelProp]); - statements.push( - exportAsyncDeclareFunction( - prefetchFnName, - null, - [createFunctionParam('queryClient', typeRef('QueryClient')), createFunctionParam('params', p2ParamType, true)], - typeRef('Promise', [t.tsVoidKeyword()]) - ) - ); - // Implementation const pImplSelProp = t.tsPropertySignature( t.identifier('selection'), t.tsTypeAnnotation(listSelectionConfigType(typeRef(selectTypeName), filterTypeName, orderByTypeName)) ); - pImplSelProp.optional = true; const pImplParamType = hasRelationships && useCentralizedKeys ? t.tsIntersectionType([t.tsTypeLiteral([pImplSelProp]), scopeTypeLiteral(scopeTypeName)]) : t.tsTypeLiteral([pImplSelProp]); @@ -427,7 +362,7 @@ export function generateListQueryHook( exportAsyncFunction( prefetchFnName, null, - [createFunctionParam('queryClient', typeRef('QueryClient')), createFunctionParam('params', pImplParamType, true)], + [createFunctionParam('queryClient', typeRef('QueryClient')), createFunctionParam('params', pImplParamType)], pBody, t.tsVoidKeyword() ) @@ -467,7 +402,6 @@ export function generateSingleQueryHook( const pkField = pkFields[0]; const pkFieldName = pkField?.name ?? 'id'; const pkFieldTsType = pkField?.tsType ?? 'string'; - const defaultFieldName = getDefaultSelectFieldName(table); const pkTsType: t.TSType = pkFieldTsType === 'string' ? t.tsStringKeyword() : t.tsNumberKeyword(); const singleResultTypeAST = (sel: t.TSType) => singleQueryResultType(queryName, relationTypeName, sel); @@ -496,9 +430,6 @@ export function generateSingleQueryHook( // Re-exports statements.push(createTypeReExport([selectTypeName, relationTypeName], '../../orm/input-types')); - // Default select - statements.push(constDecl('defaultSelect', asConst(t.objectExpression([objectProp(defaultFieldName, t.booleanLiteral(true))])))); - // Query key if (useCentralizedKeys) { const keyDecl = t.exportNamedDeclaration( @@ -534,7 +465,7 @@ export function generateSingleQueryHook( // Helper for findOne queryFn const buildFindOneFn = () => t.arrowFunctionExpression( [], - buildFindOneCallExpr(singularName, pkFieldName, 'args', selectTypeName) + buildFindOneCallExpr(singularName, pkFieldName, 'args') ); // Options type builder with optional scope @@ -594,35 +525,11 @@ export function generateSingleQueryHook( addJSDocComment(o1, docLines); statements.push(o1); - // Overload 2: without fields - const o2SelProp = t.tsPropertySignature( - t.identifier('selection'), - t.tsTypeAnnotation(withoutFieldsSelectionType()) - ); - o2SelProp.optional = true; - const o2Props = [ - t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)), - o2SelProp - ]; - const o2ParamType = t.tsIntersectionType([ - t.tsTypeLiteral(o2Props), - buildSingleOptionsType(singleResultTypeAST(typeofRef('defaultSelect')), typeRef('TData')) - ]); - statements.push( - exportDeclareFunction( - hookName, - createTDataTypeParam(singleResultTypeAST(typeofRef('defaultSelect'))), - [createFunctionParam('params', o2ParamType)], - typeRef('UseQueryResult', [typeRef('TData')]) - ) - ); - // Implementation const implSelProp = t.tsPropertySignature( t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName))) ); - implSelProp.optional = true; const implProps = [ t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)), implSelProp @@ -698,31 +605,11 @@ export function generateSingleQueryHook( ]); statements.push(f1Decl); - // Overload 2: without fields - const f2SelProp = t.tsPropertySignature( - t.identifier('selection'), - t.tsTypeAnnotation(withoutFieldsSelectionType()) - ); - f2SelProp.optional = true; - const f2Props = [ - t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)), - f2SelProp - ]; - statements.push( - exportAsyncDeclareFunction( - fetchFnName, - null, - [createFunctionParam('params', t.tsTypeLiteral(f2Props))], - typeRef('Promise', [singleResultTypeAST(typeofRef('defaultSelect'))]) - ) - ); - // Implementation const fImplSelProp = t.tsPropertySignature( t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName))) ); - fImplSelProp.optional = true; const fImplProps = [ t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)), fImplSelProp @@ -734,7 +621,7 @@ export function generateSingleQueryHook( // @ts-ignore fArgsCall.typeParameters = t.tsTypeParameterInstantiation([typeRef(selectTypeName)]); fBody.push(constDecl('args', fArgsCall)); - fBody.push(t.returnStatement(buildFindOneCallExpr(singularName, pkFieldName, 'args', selectTypeName))); + fBody.push(t.returnStatement(buildFindOneCallExpr(singularName, pkFieldName, 'args'))); statements.push(exportAsyncFunction(fetchFnName, null, [createFunctionParam('params', t.tsTypeLiteral(fImplProps))], fBody)); } @@ -766,34 +653,11 @@ export function generateSingleQueryHook( ]); statements.push(p1Decl); - // Overload 2: without fields - const p2SelProp = t.tsPropertySignature( - t.identifier('selection'), - t.tsTypeAnnotation(withoutFieldsSelectionType()) - ); - p2SelProp.optional = true; - const p2Props: t.TSPropertySignature[] = [ - t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)), - p2SelProp - ]; - const p2ParamType = hasRelationships && useCentralizedKeys - ? t.tsIntersectionType([t.tsTypeLiteral(p2Props), scopeTypeLiteral(scopeTypeName)]) - : t.tsTypeLiteral(p2Props); - statements.push( - exportAsyncDeclareFunction( - prefetchFnName, - null, - [createFunctionParam('queryClient', typeRef('QueryClient')), createFunctionParam('params', p2ParamType)], - typeRef('Promise', [t.tsVoidKeyword()]) - ) - ); - // Implementation const pImplSelProp = t.tsPropertySignature( t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName))) ); - pImplSelProp.optional = true; const pImplProps: t.TSPropertySignature[] = [ t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)), pImplSelProp diff --git a/graphql/codegen/src/core/codegen/select-helpers.ts b/graphql/codegen/src/core/codegen/select-helpers.ts index 4ae52a351..6360672b2 100644 --- a/graphql/codegen/src/core/codegen/select-helpers.ts +++ b/graphql/codegen/src/core/codegen/select-helpers.ts @@ -3,7 +3,7 @@ * * Used by custom-queries.ts, custom-mutations.ts, and orm/custom-ops-generator.ts */ -import type { CleanArgument, TypeRegistry } from '../../types/schema'; +import type { CleanArgument } from '../../types/schema'; import { SCALAR_NAMES } from './scalars'; import { getTypeBaseName } from './type-resolver'; @@ -50,42 +50,3 @@ export function wrapInferSelectResult( return `InferSelectResult<${payloadTypeName}, ${selectType}>`; } - -/** - * Build a default select literal string for a given type. - * Finds an 'id' or 'nodeId' field, or falls back to first scalar field. - */ -export function buildDefaultSelectLiteral( - typeName: string, - typeRegistry: TypeRegistry, - depth: number = 0 -): string { - const resolved = typeRegistry.get(typeName); - const fields = resolved?.fields ?? []; - - if (depth > 3 || fields.length === 0) { - // Use first field if available, otherwise fallback to 'id' - return fields.length > 0 ? `{ ${fields[0].name}: true }` : `{ id: true }`; - } - - const idLike = fields.find((f) => f.name === 'id' || f.name === 'nodeId'); - if (idLike) return `{ ${idLike.name}: true }`; - - const scalarField = fields.find((f) => { - const baseName = getTypeBaseName(f.type); - if (!baseName) return false; - if (NON_SELECT_TYPES.has(baseName)) return true; - return typeRegistry.get(baseName)?.kind === 'ENUM'; - }); - if (scalarField) return `{ ${scalarField.name}: true }`; - - const first = fields[0]; - - const firstBase = getTypeBaseName(first.type); - if (!firstBase || NON_SELECT_TYPES.has(firstBase) || typeRegistry.get(firstBase)?.kind === 'ENUM') { - return `{ ${first.name}: true }`; - } - - const nested = buildDefaultSelectLiteral(firstBase, typeRegistry, depth + 1); - return `{ ${first.name}: { select: ${nested} } }`; -} diff --git a/graphql/codegen/src/core/codegen/utils.ts b/graphql/codegen/src/core/codegen/utils.ts index 859a67900..2bca88ad7 100644 --- a/graphql/codegen/src/core/codegen/utils.ts +++ b/graphql/codegen/src/core/codegen/utils.ts @@ -401,36 +401,6 @@ export function hasValidPrimaryKey(table: CleanTable): boolean { return false; } -/** - * Get the best field name for a defaultSelect literal. - * Prefers PK field if valid, then 'id'/'nodeId', then first scalar field. - * Unlike getPrimaryKeyInfo(), never returns a fictional 'id' fallback. - */ -export function getDefaultSelectFieldName(table: CleanTable): string { - // 1. Try the actual primary key - const pk = table.constraints?.primaryKey?.[0]; - if (pk && pk.fields.length >= 1) { - return pk.fields[0].name; - } - // 2. Try id / nodeId fields - const idField = table.fields.find((f) => f.name === 'id' || f.name === 'nodeId'); - if (idField) { - return idField.name; - } - // 3. First non-array scalar field - const scalarField = table.fields.find( - (f) => !f.type.isArray && scalarToTsType(f.type.gqlType) !== f.type.gqlType - ); - if (scalarField) { - return scalarField.name; - } - // 4. First field of any kind - if (table.fields.length > 0) { - return table.fields[0].name; - } - return 'id'; -} - // ============================================================================ // Query key generation // ============================================================================ From 838705649dc40b4f8bdda3185231927a7b04862f Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sun, 8 Feb 2026 00:15:32 +0000 Subject: [PATCH 10/17] chore: update makage to 0.1.12 (fix ENOTEMPTY race condition) --- functions/send-email-link/package.json | 2 +- functions/simple-email/package.json | 2 +- graphile/graphile-cache/package.json | 2 +- graphile/graphile-i18n/package.json | 2 +- graphile/graphile-many-to-many/package.json | 2 +- graphile/graphile-meta-schema/package.json | 2 +- .../graphile-pg-type-mappings/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- graphile/graphile-postgis/package.json | 2 +- graphile/graphile-query/package.json | 2 +- graphile/graphile-search-plugin/package.json | 2 +- graphile/graphile-settings/package.json | 2 +- .../graphile-simple-inflector/package.json | 2 +- .../package.json | 2 +- graphile/graphile-test/package.json | 2 +- graphile/graphile-upload-plugin/package.json | 2 +- graphql/env/package.json | 2 +- graphql/explorer/package.json | 2 +- graphql/gql-ast/package.json | 2 +- graphql/playwright-test/package.json | 2 +- graphql/query/package.json | 2 +- graphql/react/package.json | 2 +- graphql/server-test/package.json | 2 +- graphql/server/package.json | 2 +- graphql/test/package.json | 2 +- graphql/types/package.json | 2 +- jobs/job-pg/package.json | 2 +- jobs/job-scheduler/package.json | 2 +- jobs/job-utils/package.json | 2 +- jobs/job-worker/package.json | 2 +- jobs/knative-job-example/package.json | 2 +- jobs/knative-job-fn/package.json | 2 +- jobs/knative-job-server/package.json | 2 +- jobs/knative-job-service/package.json | 2 +- jobs/knative-job-worker/package.json | 2 +- package.json | 2 +- packages/12factor-env/package.json | 2 +- packages/cli/package.json | 2 +- packages/client/package.json | 2 +- packages/csrf/package.json | 2 +- packages/csv-to-pg/package.json | 2 +- packages/oauth/package.json | 2 +- packages/orm/package.json | 2 +- packages/postmaster/package.json | 2 +- packages/query-builder/package.json | 2 +- packages/server-utils/package.json | 2 +- packages/smtppostmaster/package.json | 2 +- packages/url-domains/package.json | 2 +- pgpm/cli/package.json | 2 +- pgpm/core/package.json | 2 +- pgpm/env/package.json | 2 +- pgpm/logger/package.json | 2 +- pgpm/types/package.json | 2 +- pnpm-lock.yaml | 349 ++++++++++-------- postgres/drizzle-orm-test/package.json | 2 +- postgres/introspectron/package.json | 2 +- postgres/pg-ast/package.json | 2 +- postgres/pg-cache/package.json | 2 +- postgres/pg-codegen/package.json | 2 +- postgres/pg-env/package.json | 2 +- postgres/pg-query-context/package.json | 2 +- postgres/pg-seed/package.json | 2 +- postgres/pgsql-client/package.json | 2 +- postgres/pgsql-seed/package.json | 2 +- postgres/pgsql-test/package.json | 2 +- postgres/supabase-test/package.json | 2 +- uploads/content-type-stream/package.json | 2 +- uploads/etag-hash/package.json | 2 +- uploads/etag-stream/package.json | 2 +- uploads/mime-bytes/package.json | 2 +- uploads/s3-streamer/package.json | 2 +- uploads/s3-utils/package.json | 2 +- uploads/stream-to-etag/package.json | 2 +- uploads/upload-names/package.json | 2 +- uploads/uuid-hash/package.json | 2 +- uploads/uuid-stream/package.json | 2 +- 78 files changed, 263 insertions(+), 240 deletions(-) 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/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/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 a784ca712..9d280286c 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/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/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 b329b3a2c..27e20e30b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -53,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 @@ -99,8 +99,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: @@ -122,8 +122,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: @@ -148,8 +148,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 @@ -198,8 +198,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 @@ -224,8 +224,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 @@ -259,8 +259,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 @@ -282,8 +282,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 @@ -317,8 +317,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 @@ -355,8 +355,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 @@ -393,8 +393,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 @@ -428,8 +428,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 @@ -451,8 +451,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: @@ -477,8 +477,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 @@ -575,8 +575,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 @@ -601,8 +601,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 @@ -624,8 +624,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) @@ -665,8 +665,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: @@ -706,8 +706,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 @@ -827,8 +827,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: @@ -889,8 +889,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 @@ -906,8 +906,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: @@ -953,8 +953,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: @@ -973,8 +973,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: @@ -1008,8 +1008,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: @@ -1136,8 +1136,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 @@ -1192,8 +1192,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: @@ -1236,8 +1236,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 graphql/test-app: @@ -1311,8 +1311,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: @@ -1328,8 +1328,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: @@ -1348,8 +1348,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: @@ -1371,8 +1371,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: @@ -1388,8 +1388,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: @@ -1399,8 +1399,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: @@ -1416,8 +1416,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: @@ -1442,8 +1442,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: @@ -1522,8 +1522,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 @@ -1563,8 +1563,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 @@ -1580,8 +1580,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) @@ -1666,8 +1666,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 @@ -1686,8 +1686,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: @@ -1696,8 +1696,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) @@ -1728,8 +1728,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 @@ -1745,8 +1745,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) @@ -1762,8 +1762,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: @@ -1779,15 +1779,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: @@ -1815,8 +1815,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) @@ -1841,8 +1841,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 @@ -1861,8 +1861,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: @@ -1938,8 +1938,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 @@ -2012,8 +2012,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: @@ -2026,8 +2026,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: @@ -2037,8 +2037,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: @@ -2048,8 +2048,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: @@ -2068,8 +2068,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: @@ -2094,8 +2094,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 @@ -2111,8 +2111,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 @@ -2143,8 +2143,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: @@ -2184,15 +2184,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: @@ -2205,8 +2205,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: @@ -2228,8 +2228,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: @@ -2254,8 +2254,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: @@ -2280,8 +2280,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: @@ -2324,8 +2324,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: @@ -2344,8 +2344,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: @@ -2361,15 +2361,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: @@ -2382,8 +2382,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: @@ -2392,8 +2392,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: @@ -2421,8 +2421,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: @@ -2438,8 +2438,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: @@ -2452,8 +2452,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: @@ -2462,15 +2462,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: @@ -2480,8 +2480,8 @@ 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: @@ -3409,10 +3409,18 @@ packages: 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'} + '@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==} @@ -6226,6 +6234,7 @@ packages: glob@11.1.0: 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: @@ -6655,8 +6664,8 @@ packages: 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==} + jackspeak@4.2.3: + resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==} engines: {node: 20 || >=22} jake@10.9.4: @@ -7050,8 +7059,8 @@ packages: resolution: {integrity: sha512-YrdaZEAJwwjXGBTfZTNQ1LM7tmkdUaz2NpZEu7+zULcG4Wrlhd7cWSNZW0bxT3bP48k5N0mZWz8C2f9gc2+Geg==} engines: {node: '>=18.0.0'} - makage@0.1.10: - resolution: {integrity: sha512-IQKuRbHOrDgVNlydle+XRO5iMyaozBq4Bb9vhEzwxtvzyk08JkQo5qpfFRep0dSum53gECdX2gBoTmkWDHIfJA==} + makage@0.1.12: + resolution: {integrity: sha512-R3bITl50Ts2GzoaErywe8n24Iu2qbvbNOqOyidjDjh6iqK0CAj2VzIk3xRS4z8Q4xDQzaJrcb2+dGDjqRj6ChA==} hasBin: true make-dir@2.1.0: @@ -7157,6 +7166,10 @@ packages: 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==} @@ -10383,6 +10396,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 @@ -10392,6 +10409,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': @@ -13782,8 +13801,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 @@ -14261,9 +14280,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: @@ -14929,7 +14948,7 @@ snapshots: transitivePeerDependencies: - debug - makage@0.1.10: + makage@0.1.12: dependencies: glob: 11.1.0 yaml: 2.8.2 @@ -15034,6 +15053,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 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" } } From 6cce350b4e8079e10de87751621c4a16561f41f9 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sun, 8 Feb 2026 01:58:12 +0000 Subject: [PATCH 11/17] feat(codegen): add fire-and-forget overload for delete hooks (clientMutationId default) --- .../react-query-hooks.test.ts.snap | 84 +++++++++++++++++-- graphql/codegen/src/core/codegen/mutations.ts | 32 ++++++- 2 files changed, 109 insertions(+), 7 deletions(-) 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 fd0eeef96..6236bea78 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 @@ -917,7 +917,7 @@ 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 @@ -945,8 +945,32 @@ export function useDeleteUserMutation(params: { }, Error, { id: string; }>; +/** + * Fire-and-forget mutation hook for deleting a User + * Returns only clientMutationId (no entity data selected) + * + * @example + * \`\`\`tsx + * const { mutate, isPending } = useDeleteUserMutation(); + * + * mutate({ id: 'value-to-delete' }); + * \`\`\` + */ +export function useDeleteUserMutation(params?: Omit, "mutationFn">): UseMutationResult<{ + deleteUser: { + clientMutationId: string; + }; +}, Error, { + id: string; +}>; export function useDeleteUserMutation(params: { - selection: SelectionConfig; + selection?: SelectionConfig; } & Omit, "mutationFn">) { @@ -1001,7 +1025,7 @@ 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 @@ -1029,8 +1053,32 @@ export function useDeletePostMutation(params: { }, Error, { id: string; }>; +/** + * Fire-and-forget mutation hook for deleting a Post + * Returns only clientMutationId (no entity data selected) + * + * @example + * \`\`\`tsx + * const { mutate, isPending } = useDeletePostMutation(); + * + * mutate({ id: 'value-to-delete' }); + * \`\`\` + */ +export function useDeletePostMutation(params?: Omit, "mutationFn">): UseMutationResult<{ + deletePost: { + clientMutationId: string; + }; +}, Error, { + id: string; +}>; export function useDeletePostMutation(params: { - selection: SelectionConfig; + selection?: SelectionConfig; } & Omit, "mutationFn">) { @@ -1083,7 +1131,7 @@ 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 @@ -1111,8 +1159,32 @@ export function useDeleteUserMutation(params: { }, Error, { id: string; }>; +/** + * Fire-and-forget mutation hook for deleting a User + * Returns only clientMutationId (no entity data selected) + * + * @example + * \`\`\`tsx + * const { mutate, isPending } = useDeleteUserMutation(); + * + * mutate({ id: 'value-to-delete' }); + * \`\`\` + */ +export function useDeleteUserMutation(params?: Omit, "mutationFn">): UseMutationResult<{ + deleteUser: { + clientMutationId: string; + }; +}, Error, { + id: string; +}>; export function useDeleteUserMutation(params: { - selection: SelectionConfig; + selection?: SelectionConfig; } & Omit, "mutationFn">) { diff --git a/graphql/codegen/src/core/codegen/mutations.ts b/graphql/codegen/src/core/codegen/mutations.ts index 3814f15f3..ce29f23ed 100644 --- a/graphql/codegen/src/core/codegen/mutations.ts +++ b/graphql/codegen/src/core/codegen/mutations.ts @@ -443,6 +443,14 @@ export function generateDeleteMutationHook( const resultType = (sel: t.TSType) => buildMutationResultType(mutationName, singularName, relationTypeName, sel); + const clientMutationIdResultType = t.tsTypeLiteral([ + t.tsPropertySignature(t.identifier(mutationName), t.tsTypeAnnotation( + t.tsTypeLiteral([ + t.tsPropertySignature(t.identifier('clientMutationId'), t.tsTypeAnnotation(t.tsStringKeyword())) + ]) + )) + ]); + // Overload 1: with fields const o1ParamType = t.tsIntersectionType([ t.tsTypeLiteral([ @@ -457,7 +465,7 @@ export function generateDeleteMutationHook( useMutationResultType(resultType(sRef()), deleteVarType) ); addJSDocComment(o1, [ - `Mutation hook for deleting a ${typeName}`, + `Mutation hook for deleting a ${typeName} with typed selection`, '', '@example', '```tsx', @@ -470,8 +478,30 @@ export function generateDeleteMutationHook( ]); statements.push(o1); + // Overload 2: fire-and-forget (no selection, returns clientMutationId only) + const o2ParamType = useMutationOptionsType(clientMutationIdResultType, deleteVarType); + const o2 = exportDeclareFunction( + hookName, + null, + [createFunctionParam('params', o2ParamType, true)], + useMutationResultType(clientMutationIdResultType, deleteVarType) + ); + addJSDocComment(o2, [ + `Fire-and-forget mutation hook for deleting a ${typeName}`, + 'Returns only clientMutationId (no entity data selected)', + '', + '@example', + '```tsx', + `const { mutate, isPending } = ${hookName}();`, + '', + `mutate({ ${pkField.name}: ${pkField.tsType === 'string' ? "'value-to-delete'" : '123'} });`, + '```' + ]); + statements.push(o2); + // Implementation const implSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName)))); + implSelProp.optional = true; const implParamType = t.tsIntersectionType([ t.tsTypeLiteral([implSelProp]), omitType(typeRef('UseMutationOptions', [t.tsAnyKeyword(), typeRef('Error'), deleteVarType]), ['mutationFn']) From 1485b96d43de1828f036eed68cfa4fa6f2e515e6 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sun, 8 Feb 2026 03:30:19 +0000 Subject: [PATCH 12/17] chore(ci): add examples/codegen-integration and clean workflows (remove ignores; separate examples job) --- .github/workflows/examples-integration.yaml | 22 +++++++++++++++++++ .github/workflows/notify-e2e.yml | 3 --- .github/workflows/run-tests.yaml | 8 +------ .../codegen-integration/codegen.config.ts | 14 ++++++++++++ examples/codegen-integration/package.json | 19 ++++++++++++++++ examples/codegen-integration/src/index.ts | 2 ++ examples/codegen-integration/tsconfig.json | 14 ++++++++++++ pnpm-workspace.yaml | 1 + 8 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/examples-integration.yaml create mode 100644 examples/codegen-integration/codegen.config.ts create mode 100644 examples/codegen-integration/package.json create mode 100644 examples/codegen-integration/src/index.ts create mode 100644 examples/codegen-integration/tsconfig.json diff --git a/.github/workflows/examples-integration.yaml b/.github/workflows/examples-integration.yaml new file mode 100644 index 000000000..41873a116 --- /dev/null +++ b/.github/workflows/examples-integration.yaml @@ -0,0 +1,22 @@ +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 + - run: pnpm -r --filter @constructive-io/examples-codegen-integration run test:types diff --git a/.github/workflows/notify-e2e.yml b/.github/workflows/notify-e2e.yml index 7f9e6f3d6..e12a58c6a 100644 --- a/.github/workflows/notify-e2e.yml +++ b/.github/workflows/notify-e2e.yml @@ -6,9 +6,6 @@ name: Notify E2E Tests on: push: branches: [main] - paths-ignore: - - 'graphql/test-app/**' - - 'graphql/test-codegen-app/**' jobs: trigger-tests: diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 015753008..c7d75dfa1 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -4,16 +4,10 @@ on: branches: - main - v1 - paths-ignore: - - 'graphql/test-app/**' - - 'graphql/test-codegen-app/**' pull_request: branches: - main - v1 - paths-ignore: - - 'graphql/test-app/**' - - 'graphql/test-codegen-app/**' workflow_dispatch: workflow_call: @@ -197,7 +191,7 @@ jobs: - name: build run: | - pnpm -r --filter '!@constructive-io/test-codegen-app' run build + pnpm -r --filter '!./examples/**' run build - name: seed app_user run: | 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..f7c3864b4 --- /dev/null +++ b/examples/codegen-integration/package.json @@ -0,0 +1,19 @@ +{ + "name": "@constructive-io/examples-codegen-integration", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "codegen": "tsx ../../graphql/codegen/src/cli/index.ts --config codegen.config.ts", + "test:types": "pnpm run codegen && tsc --noEmit" + }, + "dependencies": { + "graphql": "15.10.1" + }, + "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/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/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/*' From c4ecef3bcc121225c0420e0cad8274e130fe92c3 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sun, 8 Feb 2026 03:36:20 +0000 Subject: [PATCH 13/17] chore: fix codegen runner, add missing deps, update build filters for examples --- .github/workflows/examples-integration.yaml | 2 +- examples/codegen-integration/.gitignore | 1 + examples/codegen-integration/package.json | 13 ++++-- .../scripts/codegen-runner.ts | 26 ++++++++++++ package.json | 4 +- pnpm-lock.yaml | 40 ++++++++++++++++++- 6 files changed, 77 insertions(+), 9 deletions(-) create mode 100644 examples/codegen-integration/.gitignore create mode 100644 examples/codegen-integration/scripts/codegen-runner.ts diff --git a/.github/workflows/examples-integration.yaml b/.github/workflows/examples-integration.yaml index 41873a116..de0fd19a6 100644 --- a/.github/workflows/examples-integration.yaml +++ b/.github/workflows/examples-integration.yaml @@ -19,4 +19,4 @@ jobs: with: version: 10 - run: pnpm install - - run: pnpm -r --filter @constructive-io/examples-codegen-integration run test:types + - run: pnpm -r --filter @constructive-io/examples-codegen-integration run test:codegen 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/package.json b/examples/codegen-integration/package.json index f7c3864b4..d7990a228 100644 --- a/examples/codegen-integration/package.json +++ b/examples/codegen-integration/package.json @@ -2,13 +2,18 @@ "name": "@constructive-io/examples-codegen-integration", "version": "0.0.0", "private": true, - "type": "module", "scripts": { - "codegen": "tsx ../../graphql/codegen/src/cli/index.ts --config codegen.config.ts", - "test:types": "pnpm run codegen && tsc --noEmit" + "codegen": "tsx scripts/codegen-runner.ts", + "test:types": "pnpm run codegen && tsc --noEmit", + "test:codegen": "pnpm run codegen" }, "dependencies": { - "graphql": "15.10.1" + "@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:^", diff --git a/examples/codegen-integration/scripts/codegen-runner.ts b/examples/codegen-integration/scripts/codegen-runner.ts new file mode 100644 index 000000000..38ad8e9d4 --- /dev/null +++ b/examples/codegen-integration/scripts/codegen-runner.ts @@ -0,0 +1,26 @@ +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, + codegen: { + maxFieldDepth: 2, + skipQueryField: true + } + }); + + if (!result.success) { + console.error(result.message); + process.exit(1); + } + + console.log(result.message); +} + +run(); diff --git a/package.json b/package.json index 9d280286c..81430d81a 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ }, "scripts": { "clean": "pnpm -r run clean", - "build": "pnpm -r --filter '!@constructive-io/test-codegen-app' run build", - "build:dev": "pnpm -r --filter '!@constructive-io/test-codegen-app' run build:dev", + "build": "pnpm -r --filter '!./examples/**' run build", + "build:dev": "pnpm -r --filter '!./examples/**' run build:dev", "lint": "pnpm -r run lint", "internal:deps": "makage update-workspace", "deps": "pnpm up -r -i -L" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 27e20e30b..95c7ea774 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,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': @@ -6229,6 +6263,7 @@ packages: glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@11.1.0: @@ -6243,11 +6278,12 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + 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'} + 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==} @@ -8533,7 +8569,7 @@ packages: 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 + 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==} From fe2308aea7913ce93a3b9004a0b69e1bffed2177 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sun, 8 Feb 2026 03:41:24 +0000 Subject: [PATCH 14/17] fix: keep test-codegen-app exclusion alongside examples filter in build --- .github/workflows/run-tests.yaml | 2 +- package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index c7d75dfa1..96a9d7d83 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -191,7 +191,7 @@ jobs: - name: build run: | - pnpm -r --filter '!./examples/**' run build + pnpm -r --filter '!./examples/**' --filter '!@constructive-io/test-codegen-app' run build - name: seed app_user run: | diff --git a/package.json b/package.json index 81430d81a..9ff59a85d 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ }, "scripts": { "clean": "pnpm -r run clean", - "build": "pnpm -r --filter '!./examples/**' run build", - "build:dev": "pnpm -r --filter '!./examples/**' run build:dev", + "build": "pnpm -r --filter '!./examples/**' --filter '!@constructive-io/test-codegen-app' run build", + "build:dev": "pnpm -r --filter '!./examples/**' --filter '!@constructive-io/test-codegen-app' run build:dev", "lint": "pnpm -r run lint", "internal:deps": "makage update-workspace", "deps": "pnpm up -r -i -L" From 1f2d244b59895b1a0669f83f0893f61504d7b27c Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sun, 8 Feb 2026 03:49:25 +0000 Subject: [PATCH 15/17] fix(ci): add build step to examples-integration workflow for workspace deps --- .github/workflows/examples-integration.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/examples-integration.yaml b/.github/workflows/examples-integration.yaml index de0fd19a6..e64e5daa4 100644 --- a/.github/workflows/examples-integration.yaml +++ b/.github/workflows/examples-integration.yaml @@ -19,4 +19,6 @@ jobs: with: version: 10 - run: pnpm install + - name: Build codegen and dependencies + run: pnpm -r --filter '!./examples/**' --filter '!@constructive-io/test-codegen-app' run build - run: pnpm -r --filter @constructive-io/examples-codegen-integration run test:codegen From a9bf4dd3b893c757ad724b9ea68078f421ff7345 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sun, 8 Feb 2026 05:45:57 +0000 Subject: [PATCH 16/17] chore(ci): remove all paths-ignore and build filter hacks; rename test-codegen-app build to build:app --- .github/workflows/docker-launchql.yaml | 6 ------ .github/workflows/examples-integration.yaml | 2 +- .github/workflows/run-tests.yaml | 3 +-- graphql/test-app/package.json | 2 +- package.json | 4 ++-- 5 files changed, 5 insertions(+), 12 deletions(-) diff --git a/.github/workflows/docker-launchql.yaml b/.github/workflows/docker-launchql.yaml index abf4d3196..13856efc6 100644 --- a/.github/workflows/docker-launchql.yaml +++ b/.github/workflows/docker-launchql.yaml @@ -6,17 +6,11 @@ on: - main - v1 - release/* - paths-ignore: - - 'graphql/test-app/**' - - 'graphql/test-codegen-app/**' pull_request: branches: - main - v1 types: [opened, reopened, synchronize, ready_for_review] - paths-ignore: - - 'graphql/test-app/**' - - 'graphql/test-codegen-app/**' workflow_dispatch: {} concurrency: diff --git a/.github/workflows/examples-integration.yaml b/.github/workflows/examples-integration.yaml index e64e5daa4..418e9396e 100644 --- a/.github/workflows/examples-integration.yaml +++ b/.github/workflows/examples-integration.yaml @@ -20,5 +20,5 @@ jobs: version: 10 - run: pnpm install - name: Build codegen and dependencies - run: pnpm -r --filter '!./examples/**' --filter '!@constructive-io/test-codegen-app' run build + run: pnpm run build - run: pnpm -r --filter @constructive-io/examples-codegen-integration run test:codegen diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 96a9d7d83..3142fb930 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -190,8 +190,7 @@ jobs: run: pnpm install - name: build - run: | - pnpm -r --filter '!./examples/**' --filter '!@constructive-io/test-codegen-app' run build + run: pnpm run build - name: seed app_user run: | diff --git a/graphql/test-app/package.json b/graphql/test-app/package.json index 139ad00f0..a1a3619f5 100644 --- a/graphql/test-app/package.json +++ b/graphql/test-app/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "dev": "vite", - "build": "tsc -b && vite build", + "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", diff --git a/package.json b/package.json index 9ff59a85d..9c215bbf4 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ }, "scripts": { "clean": "pnpm -r run clean", - "build": "pnpm -r --filter '!./examples/**' --filter '!@constructive-io/test-codegen-app' run build", - "build:dev": "pnpm -r --filter '!./examples/**' --filter '!@constructive-io/test-codegen-app' run build:dev", + "build": "pnpm -r run build", + "build:dev": "pnpm -r run build:dev", "lint": "pnpm -r run lint", "internal:deps": "makage update-workspace", "deps": "pnpm up -r -i -L" From fd0f8e275f5f77a719595f41635b997d4a288573 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sun, 8 Feb 2026 05:48:38 +0000 Subject: [PATCH 17/17] chore: remove redundant codegen options (already defaults) --- examples/codegen-integration/scripts/codegen-runner.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/examples/codegen-integration/scripts/codegen-runner.ts b/examples/codegen-integration/scripts/codegen-runner.ts index 38ad8e9d4..1c4f62066 100644 --- a/examples/codegen-integration/scripts/codegen-runner.ts +++ b/examples/codegen-integration/scripts/codegen-runner.ts @@ -8,11 +8,7 @@ async function run() { schemaFile: path.resolve(root, '../../graphql/codegen/examples/example.schema.graphql'), output: path.resolve(root, 'src/generated'), reactQuery: true, - orm: true, - codegen: { - maxFieldDepth: 2, - skipQueryField: true - } + orm: true }); if (!result.success) {