@fitzzero/quickdraw-core 5.1.1 → 5.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1308 -219
- package/dist/{admin-DKwkIh5i.d.ts → admin-CS7JB_UH.d.ts} +2 -2
- package/dist/{adminSchemas-2DUA_hZ8.d.ts → adminSchemas-29cGgrg5.d.ts} +6 -4
- package/dist/{auth-BhWqdyb-.d.ts → auth-DtdYjrZ9.d.ts} +51 -21
- package/dist/{caller-CXTFswBO.d.ts → caller-BTwGl7vm.d.ts} +296 -33
- package/dist/chunk-2FDSKLBO.js +82 -0
- package/dist/chunk-2FDSKLBO.js.map +1 -0
- package/dist/{chunk-RT6OILOI.js → chunk-4D2DOGAW.js} +2 -14
- package/dist/chunk-4D2DOGAW.js.map +1 -0
- package/dist/{chunk-OECZPRPW.js → chunk-64I6MYBC.js} +162 -775
- package/dist/chunk-64I6MYBC.js.map +1 -0
- package/dist/chunk-7473HK24.js +17 -0
- package/dist/chunk-7473HK24.js.map +1 -0
- package/dist/chunk-7Y5ROPXL.js +33 -0
- package/dist/chunk-7Y5ROPXL.js.map +1 -0
- package/dist/chunk-A2RBQD66.js +7 -0
- package/dist/chunk-A2RBQD66.js.map +1 -0
- package/dist/chunk-AK23XSWD.js +16 -0
- package/dist/chunk-AK23XSWD.js.map +1 -0
- package/dist/chunk-ASAMUGHG.js +651 -0
- package/dist/chunk-ASAMUGHG.js.map +1 -0
- package/dist/{chunk-B2P7AZ25.js → chunk-CYE4UBOB.js} +6 -4
- package/dist/chunk-CYE4UBOB.js.map +1 -0
- package/dist/chunk-DKE6QO26.js +136 -0
- package/dist/chunk-DKE6QO26.js.map +1 -0
- package/dist/chunk-DNP65TD5.js +832 -0
- package/dist/chunk-DNP65TD5.js.map +1 -0
- package/dist/{chunk-H23KEFBA.js → chunk-DUBU3BB3.js} +30 -1
- package/dist/chunk-DUBU3BB3.js.map +1 -0
- package/dist/chunk-GYLWEJHW.js +19 -0
- package/dist/chunk-GYLWEJHW.js.map +1 -0
- package/dist/{chunk-SHEGLZEP.js → chunk-I3JCFS7H.js} +34 -13
- package/dist/chunk-I3JCFS7H.js.map +1 -0
- package/dist/{chunk-X5CWPX7H.js → chunk-IIQ3WMJK.js} +13 -2
- package/dist/chunk-IIQ3WMJK.js.map +1 -0
- package/dist/{chunk-RZTP4IEW.js → chunk-JVTONQFI.js} +6339 -4226
- package/dist/chunk-JVTONQFI.js.map +1 -0
- package/dist/{chunk-QEKVYG5F.js → chunk-KKQANRLG.js} +2 -2
- package/dist/chunk-KKQANRLG.js.map +1 -0
- package/dist/{chunk-CDKG4TFA.js → chunk-MPQAT55F.js} +38 -205
- package/dist/chunk-MPQAT55F.js.map +1 -0
- package/dist/chunk-NO4M6PO5.js +101 -0
- package/dist/chunk-NO4M6PO5.js.map +1 -0
- package/dist/{chunk-TBMKJ26R.js → chunk-NW6U45HX.js} +3 -1
- package/dist/chunk-NW6U45HX.js.map +1 -0
- package/dist/chunk-NX2V6SIL.js +202 -0
- package/dist/chunk-NX2V6SIL.js.map +1 -0
- package/dist/{chunk-ZIVPHYRG.js → chunk-NZHA4TZD.js} +72 -175
- package/dist/chunk-NZHA4TZD.js.map +1 -0
- package/dist/{chunk-2PWMUVC7.js → chunk-OCZJ4EYV.js} +518 -27
- package/dist/chunk-OCZJ4EYV.js.map +1 -0
- package/dist/{chunk-REX5YPHX.js → chunk-PHCURHC7.js} +76 -21
- package/dist/chunk-PHCURHC7.js.map +1 -0
- package/dist/{chunk-4YO5H5ON.js → chunk-Q4OGQM5I.js} +4 -10
- package/dist/chunk-Q4OGQM5I.js.map +1 -0
- package/dist/chunk-QSU47XEX.js +13 -0
- package/dist/chunk-QSU47XEX.js.map +1 -0
- package/dist/{chunk-DD4SKCNO.js → chunk-RZXJTDH5.js} +13 -2
- package/dist/chunk-RZXJTDH5.js.map +1 -0
- package/dist/{chunk-Z2LZ7IZ7.js → chunk-SN3OZVEQ.js} +5 -31
- package/dist/chunk-SN3OZVEQ.js.map +1 -0
- package/dist/{chunk-4DIQHASK.js → chunk-SQ5VUG77.js} +28 -8
- package/dist/chunk-SQ5VUG77.js.map +1 -0
- package/dist/chunk-STH5DLQP.js +1192 -0
- package/dist/chunk-STH5DLQP.js.map +1 -0
- package/dist/{chunk-QCHKWIRS.js → chunk-VZFJTKIW.js} +13 -13
- package/dist/{chunk-QCHKWIRS.js.map → chunk-VZFJTKIW.js.map} +1 -1
- package/dist/{chunk-VSQBHPWH.js → chunk-X4ZU4QH5.js} +54 -22
- package/dist/chunk-X4ZU4QH5.js.map +1 -0
- package/dist/chunk-XD7SRDUY.js +188 -0
- package/dist/chunk-XD7SRDUY.js.map +1 -0
- package/dist/chunk-XH2IZVLT.js +62 -0
- package/dist/chunk-XH2IZVLT.js.map +1 -0
- package/dist/chunk-Z7I6SONO.js +825 -0
- package/dist/chunk-Z7I6SONO.js.map +1 -0
- package/dist/cli/quickdraw-docs.js +132 -112
- package/dist/cli/quickdraw-docs.js.map +1 -1
- package/dist/client/core.d.ts +387 -0
- package/dist/client/core.js +109 -0
- package/dist/client/index.d.ts +52 -203
- package/dist/client/index.js +59 -218
- package/dist/client/index.js.map +1 -1
- package/dist/{clientTypes-Bc-G8n-U.d.ts → clientTypes-CUUNJwWs.d.ts} +3 -3
- package/dist/{connection-Cr1BU07W.d.ts → connection-2EeQ_Et0.d.ts} +22 -11
- package/dist/{createServer-CP9eDHZZ.d.ts → createServer-Bx5HOcYK.d.ts} +67 -17
- package/dist/{createTestApp-UKVGEmOf.d.ts → createTestApp-DAMANT79.d.ts} +46 -13
- package/dist/{envelope-Cp3YcVxC.d.ts → envelope-BMBaxppV.d.ts} +216 -10
- package/dist/{http-Djj2Inuu.d.ts → http-YzLAar3w.d.ts} +76 -60
- package/dist/index.d.ts +8 -7
- package/dist/index.js +82 -25
- package/dist/index.js.map +1 -1
- package/dist/{infer-Teo1xpsd.d.ts → infer-Br62cnyW.d.ts} +82 -11
- package/dist/logger-Yz93KzdV.d.ts +30 -0
- package/dist/{metrics-BdBu5o8G.d.ts → metrics-CTVpw0gu.d.ts} +2 -2
- package/dist/origins-kvpxnVcW.d.ts +8 -0
- package/dist/parser.js +2 -1
- package/dist/prisma/index.d.ts +14 -7
- package/dist/prisma/index.js +279 -70
- package/dist/prisma/index.js.map +1 -1
- package/dist/{rateLimit-ZMIZJUZF.js → rateLimit-5RKBFLUR.js} +2 -2
- package/dist/rateLimit-5RKBFLUR.js.map +1 -0
- package/dist/remote-N7OUAGOW.js +15 -0
- package/dist/remote-N7OUAGOW.js.map +1 -0
- package/dist/server/auth/index.d.ts +82 -33
- package/dist/server/auth/index.js +277 -270
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/express/index.d.ts +9 -2
- package/dist/server/express/index.js +1 -1
- package/dist/server/index.d.ts +268 -84
- package/dist/server/index.js +664 -418
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp/index.d.ts +89 -27
- package/dist/server/mcp/index.js +281 -62
- package/dist/server/mcp/index.js.map +1 -1
- package/dist/server/otel.d.ts +3 -3
- package/dist/{sharing-DVa8W-yR.d.ts → sharing-BrsmlDv_.d.ts} +3 -3
- package/dist/testing/client.d.ts +14 -14
- package/dist/testing/client.js +19 -10
- package/dist/testing/client.js.map +1 -1
- package/dist/testing/index.d.ts +50 -13
- package/dist/testing/index.js +113 -21
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/mock.d.ts +5 -5
- package/dist/testing/mock.js +17 -9
- package/dist/tracked-BR5b2O-U.d.ts +43 -0
- package/dist/{types-Cu0vmx7c.d.ts → types-CLRCQGnO.d.ts} +4 -3
- package/dist/types-tMagHbjy.d.ts +151 -0
- package/dist/utils/index.d.ts +16 -4
- package/dist/utils/index.js +6 -3
- package/package.json +5 -1
- package/dist/chunk-2PWMUVC7.js.map +0 -1
- package/dist/chunk-4DIQHASK.js.map +0 -1
- package/dist/chunk-4YO5H5ON.js.map +0 -1
- package/dist/chunk-B2P7AZ25.js.map +0 -1
- package/dist/chunk-CDKG4TFA.js.map +0 -1
- package/dist/chunk-DD4SKCNO.js.map +0 -1
- package/dist/chunk-H23KEFBA.js.map +0 -1
- package/dist/chunk-OECZPRPW.js.map +0 -1
- package/dist/chunk-QEKVYG5F.js.map +0 -1
- package/dist/chunk-REX5YPHX.js.map +0 -1
- package/dist/chunk-RT6OILOI.js.map +0 -1
- package/dist/chunk-RZTP4IEW.js.map +0 -1
- package/dist/chunk-SHEGLZEP.js.map +0 -1
- package/dist/chunk-TBMKJ26R.js.map +0 -1
- package/dist/chunk-VSQBHPWH.js.map +0 -1
- package/dist/chunk-X5CWPX7H.js.map +0 -1
- package/dist/chunk-YSWH776Y.js +0 -13
- package/dist/chunk-YSWH776Y.js.map +0 -1
- package/dist/chunk-Z2LZ7IZ7.js.map +0 -1
- package/dist/chunk-ZIVPHYRG.js.map +0 -1
- package/dist/logger-BY28acW-.d.ts +0 -16
- /package/dist/{rateLimit-ZMIZJUZF.js.map → client/core.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/contract/methods.ts","../src/contract/kits/schemas.ts","../src/contract/kits/crudList.ts","../src/contract/kits/crudSchemas.ts","../src/contract/kits/adminFields.ts","../src/contract/kits/adminSchemas.ts","../src/contract/kits/admin.ts"],"sourcesContent":["// Method declarations for a contract (RFC 0003 section 2). Every method is a\n// `query` or a `mutation`, and both `input` and `output` are required. This\n// replaces the 4.1 hand-written `ServiceMethodsMap` plus the optional Zod\n// schema passed to `defineMethod` (4.1 `src/server/BaseService.ts:848-851`).\n\nimport type { InferInput, StandardSchemaV1 } from \"./standardSchema\";\n\n/**\n * A query reads; a mutation writes. The kind decides request sharing,\n * cancellation, the per-socket concurrency cap, the HTTP verb, the MCP\n * read-only hint and which client hook exists.\n */\nexport type MethodKind = \"query\" | \"mutation\";\n\n/** The name of the implicit projection: the full entity. */\nexport type EntityProjection = \"entity\";\n\n/** `nullable(\"entity\")`: one row of a projection, or `null`. */\nexport interface NullableProjection<Projection extends string = string> {\n readonly kind: \"nullable\";\n readonly projection: Projection;\n}\n\n/** `listOf(\"card\")`: an array of rows of a projection. */\nexport interface ProjectionList<Projection extends string = string> {\n readonly kind: \"list\";\n readonly projection: Projection;\n}\n\n/** A method output given as a projection: its name, optionally wrapped. */\nexport type ProjectionRef<Projection extends string = string> =\n | Projection\n | NullableProjection<Projection>\n | ProjectionList<Projection>;\n\n/** What a method returns: any Standard Schema, or a projection of the entity. */\nexport type MethodOutput = StandardSchemaV1 | ProjectionRef;\n\n/**\n * Declares that a query reads one scope of one of the contract's collections.\n * The client joins that topic and invalidates the query when the scope changes\n * (RFC 0003 section 11.3). `scope` receives the input exactly as the caller\n * passed it.\n */\nexport interface Watch<Collection extends string = string, Input = never> {\n readonly collection: Collection;\n readonly scope: (input: Input) => string;\n}\n\n/**\n * `watch: { service: [\"gameScore\"] }`: the service's change topic, narrowed\n * to the models named (finding F7.3 of the quickdraw-chat review): the\n * query is invalidated only after a flush that changed one of them. The\n * names are models of the service, by the client's model name: its `model`\n * and those it lists in `writes`; `defineService` refuses any other.\n */\nexport interface ServiceModelsWatch {\n readonly service: readonly string[];\n}\n\n/**\n * `watch: \"service\"`: the query reads what the service's change topic covers\n * (its rows, its collections, and the models it lists in `writes`, such as\n * a game's high scores), so it is invalidated after every flush that\n * changes any of them. `watch: { service: [models] }` is invalidated only\n * when one of the models named changed. The service must open its topic\n * with `watchAccess`.\n */\nexport type ServiceWatch = \"service\" | ServiceModelsWatch;\n\n/** A `query` as `defineContract` stores it. */\nexport interface QueryDef<\n Input extends StandardSchemaV1 = StandardSchemaV1,\n Output extends MethodOutput = MethodOutput,\n Watched extends string = never,\n> {\n readonly kind: \"query\";\n readonly input: Input;\n readonly output: Output;\n /**\n * The topic the query watches: a collection scope (`Watched` is then the\n * collection's name), or `\"service\"`, its service's own topic, or\n * `{ service: [models] }`, that topic narrowed to the models named.\n */\n readonly watch?:\n | ([Watched] extends [never] ? ServiceWatch : Watch<Watched, InferInput<Input>>)\n | undefined;\n /** What the method does, in a sentence or two. The MCP bridge uses it as the tool's description. */\n readonly describe?: string | undefined;\n}\n\n/** A `mutation` as `defineContract` stores it. Mutations never watch. */\nexport interface MutationDef<\n Input extends StandardSchemaV1 = StandardSchemaV1,\n Output extends MethodOutput = MethodOutput,\n> {\n readonly kind: \"mutation\";\n readonly input: Input;\n readonly output: Output;\n readonly watch?: undefined;\n /** What the method does, in a sentence or two. The MCP bridge uses it as the tool's description. */\n readonly describe?: string | undefined;\n}\n\n/** Any method of any contract. */\nexport interface MethodDef {\n readonly kind: MethodKind;\n readonly input: StandardSchemaV1;\n readonly output: MethodOutput;\n readonly watch?: Watch<string> | ServiceWatch | undefined;\n readonly describe?: string | undefined;\n}\n\n/**\n * A read. `output` is a schema or a projection name (`\"entity\"` or a key of\n * the contract's `projections`), optionally wrapped in `nullable` or `listOf`.\n * `describe` says what the method does, for people and agents: the MCP\n * bridge uses it as the tool's description.\n *\n * @example\n * get: query({ input: z.object({ id: z.string() }), output: \"entity\", describe: \"Reads one task\" })\n */\nexport function query<\n const Input extends StandardSchemaV1,\n const Output extends MethodOutput,\n const Watched extends string = never,\n>(def: {\n readonly input: Input;\n readonly output: Output;\n readonly watch?: Watch<Watched, InferInput<Input>> | ServiceWatch;\n readonly describe?: string;\n}): QueryDef<Input, Output, NoInfer<Watched>> {\n // `NoInfer` in the return type: inside `defineContract`, TypeScript would\n // otherwise infer `Watched` from the surrounding contract as `string` for a\n // query that does not watch, and the watch check would then reject it.\n // Absent options stay absent rather than becoming `undefined` members.\n // A collection watch names `Watched`; `\"service\"` leaves it `never`, as the type says.\n const method = {\n kind: \"query\",\n input: def.input,\n output: def.output,\n ...(def.watch === undefined ? {} : { watch: def.watch }),\n ...(def.describe === undefined ? {} : { describe: def.describe }),\n } as QueryDef<Input, Output, Watched>;\n return Object.freeze(method);\n}\n\n/**\n * A write. `output` and `describe` follow the same rules as `query`; a\n * mutation cannot `watch`.\n *\n * @example\n * rename: mutation({ input: renameSchema, output: \"entity\" })\n */\nexport function mutation<\n const Input extends StandardSchemaV1,\n const Output extends MethodOutput,\n>(def: {\n readonly input: Input;\n readonly output: Output;\n readonly describe?: string;\n}): MutationDef<Input, Output> {\n const method: MutationDef<Input, Output> = {\n kind: \"mutation\",\n input: def.input,\n output: def.output,\n ...(def.describe === undefined ? {} : { describe: def.describe }),\n };\n return Object.freeze(method);\n}\n\n/** A method output of one projection row, or `null` when there is none. */\nexport function nullable<const Projection extends string>(\n projection: Projection,\n): NullableProjection<Projection> {\n return Object.freeze({ kind: \"nullable\", projection });\n}\n\n/** A method output of an array of projection rows. */\nexport function listOf<const Projection extends string>(\n projection: Projection,\n): ProjectionList<Projection> {\n return Object.freeze({ kind: \"list\", projection });\n}\n","// The schemas kits generate (RFC 0003 section 12): plain Standard Schemas that\n// also describe themselves as JSON Schema (Standard JSON Schema v1), so a\n// kit's methods become MCP tools like any method whose schemas come from\n// Zod 4.2 or later. Dependency-free and browser-safe, like the rest of the\n// contract layer: a kit takes the app's own schemas (any Standard Schema\n// library) and wraps them, and builds the parts it adds (ids, cursors,\n// limits) itself.\n\nimport type {\n StandardJSONSchemaV1,\n StandardSchemaV1,\n StandardSchemaWithJSON,\n} from \"../standardSchema\";\n\n/** A JSON Schema document, as a kit schema writes it. */\nexport type JsonSchema = Record<string, unknown>;\n\n/** A schema a kit generates: validation, and its JSON Schema. */\nexport type KitSchema<Input, Output = Input> = StandardSchemaWithJSON<Input, Output>;\n\n/** A schema's validation result: `{ value }` or `{ issues }`. */\nexport type Validated<Output> = StandardSchemaV1.Result<Output>;\n\ntype Validator<Output> = (value: unknown) => Validated<Output> | Promise<Validated<Output>>;\n\n/** Writes the JSON Schema of a kit schema's input and output for one target. */\nexport interface JsonWriter {\n readonly input: (target: string) => JsonSchema;\n readonly output?: (target: string) => JsonSchema;\n}\n\nconst DIALECTS: Readonly<Record<string, string>> = Object.freeze({\n \"draft-07\": \"http://json-schema.org/draft-07/schema#\",\n \"draft-2020-12\": \"https://json-schema.org/draft/2020-12/schema\",\n});\n\n/** The `$schema` of a JSON Schema target a kit schema writes, or an error for one it does not. */\nfunction dialectOf(options: StandardJSONSchemaV1.Options): string {\n const dialect = DIALECTS[options.target];\n if (dialect === undefined) {\n throw new Error(\n `quickdraw's kit schemas write JSON Schema draft-07 and draft-2020-12, not ${options.target}`,\n );\n }\n return dialect;\n}\n\n/** A Standard Schema with Standard JSON Schema, from a validator and a JSON Schema writer. */\nexport function kitSchema<Input, Output = Input>(\n validate: Validator<Output>,\n json: JsonWriter,\n): KitSchema<Input, Output> {\n const write =\n (side: (target: string) => JsonSchema) =>\n (options: StandardJSONSchemaV1.Options): Record<string, unknown> => ({\n $schema: dialectOf(options),\n ...side(options.target),\n });\n const jsonSchema = Object.freeze({\n input: write(json.input),\n output: write(json.output ?? json.input),\n });\n return Object.freeze({\n \"~standard\": Object.freeze({ version: 1, vendor: \"quickdraw\", validate, jsonSchema }),\n }) as KitSchema<Input, Output>;\n}\n\n/** A failed validation with one issue. */\nexport function invalid(message: string, path: readonly PropertyKey[] = []): Validated<never> {\n return { issues: [{ message, path: [...path] }] };\n}\n\n/** A plain object: what kit inputs are made of. */\nexport function isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** A row id: a non-empty string. */\nexport function isId(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0;\n}\n\n/** The keys of `value` that are not in `allowed`, as issues at `path`. */\nexport function unknownKeys(\n value: Readonly<Record<string, unknown>>,\n allowed: readonly string[],\n path: readonly PropertyKey[] = [],\n): StandardSchemaV1.Issue[] {\n const known = allowed.length === 0 ? \"none\" : allowed.map((key) => `\"${key}\"`).join(\", \");\n return Object.keys(value)\n .filter((key) => !allowed.includes(key))\n .map((key) => ({\n message: `Unknown key \"${key}\"; the keys are ${known}`,\n path: [...path, key],\n }));\n}\n\n/** Issues from another schema, moved under `path`. */\nexport function nested(\n issues: readonly StandardSchemaV1.Issue[],\n path: readonly PropertyKey[],\n): StandardSchemaV1.Issue[] {\n return issues.map((issue) => ({\n message: issue.message,\n path: [...path, ...(issue.path ?? [])],\n }));\n}\n\n/** The JSON Schema of a row id. */\nexport function idJson(): JsonSchema {\n return { type: \"string\", minLength: 1 };\n}\n\n/** The JSON Schema of an object with `properties`, all of `required` present and nothing else. */\nexport function objectJson(\n properties: Readonly<Record<string, JsonSchema>>,\n required: readonly string[] = [],\n): JsonSchema {\n return {\n type: \"object\",\n properties: { ...properties },\n ...(required.length === 0 ? {} : { required: [...required] }),\n additionalProperties: false,\n };\n}\n\n/** True when `schema` can describe itself as JSON Schema. */\nfunction describes(schema: StandardSchemaV1): schema is StandardSchemaWithJSON {\n const props: object = schema[\"~standard\"];\n return \"jsonSchema\" in props && isRecord(props.jsonSchema);\n}\n\n/**\n * The JSON Schema a Standard Schema writes for `target`, without its\n * `$schema` (the kit schema around it writes its own), or `undefined` when\n * the schema cannot describe itself.\n */\nexport function jsonOf(\n schema: StandardSchemaV1,\n side: \"input\" | \"output\",\n target: string,\n): JsonSchema | undefined {\n if (!describes(schema)) {\n return undefined;\n }\n const { $schema: _dialect, ...json } = schema[\"~standard\"].jsonSchema[side]({ target });\n return json;\n}\n\n/** True when `schema` can describe itself as JSON Schema: a kit schema wrapping it can too. */\nexport function hasJson(schema: StandardSchemaV1): boolean {\n return describes(schema);\n}\n","// The input and output of the read/write kit's `list` (RFC 0003 section\n// 12.1). A caller may filter and sort only on the fields the contract\n// declares, and a filter value is a plain value (equality), never an object:\n// nothing the caller sends reaches the database as an operator. The page\n// size defaults to 50 and is clamped to 200; the cursor is opaque here and\n// decoded by the server.\n\nimport type { SortDirection } from \"../collections\";\nimport type { StandardSchemaV1 } from \"../standardSchema\";\nimport {\n isRecord,\n jsonOf,\n kitSchema,\n objectJson,\n unknownKeys,\n type JsonSchema,\n type KitSchema,\n} from \"./schemas\";\n\n/** `list`'s page size when the caller gives none. */\nexport const LIST_DEFAULT_LIMIT = 50;\n\n/** The largest page `list` returns: a larger `limit` is clamped to it. */\nexport const LIST_MAX_LIMIT = 200;\n\n/** The longest cursor `list` (and `search`) accepts. */\nexport const MAX_CURSOR_LENGTH = 4096;\n\n/** A value a `list` filter compares a field with. */\nexport type FilterValue = string | number | boolean | null;\n\n/** A `list` call's sort: one declared field, ascending unless said otherwise. */\nexport interface ListSort<Field extends string = string> {\n readonly field: Field;\n readonly direction?: SortDirection;\n}\n\n/** `list`'s input as its handler receives it: defaults applied, the limit clamped. */\nexport interface ListQuery<Filter extends string = string, Sort extends string = string> {\n /** Equality per declared field; `{}` for none. */\n readonly filter: { readonly [Field in Filter]?: FilterValue };\n /** The caller's sort, or `undefined` for the default order. */\n readonly sort: { readonly field: Sort; readonly direction: SortDirection } | undefined;\n readonly cursor: string | undefined;\n /** At least 1 and at most {@link LIST_MAX_LIMIT}. */\n readonly limit: number;\n /** Whether to count every matching row, which costs a second statement. */\n readonly totalCount: boolean;\n}\n\n/** One page of `list`. */\nexport interface ListPage<Item> {\n readonly items: Item[];\n /** Passed back as `cursor` for the next page; `null` on the last page. */\n readonly nextCursor: string | null;\n /** Every row the call's filter and access match, when it asked with `totalCount: true`. */\n readonly totalCount?: number;\n}\n\n/** What `list` declares: the fields a caller may filter and sort on. */\nexport interface ListFields {\n readonly filter: readonly string[];\n readonly sort: readonly string[];\n}\n\ntype Issues = StandardSchemaV1.Issue[];\n\nfunction isFilterValue(value: unknown): value is FilterValue {\n return value === null || [\"string\", \"number\", \"boolean\"].includes(typeof value);\n}\n\nfunction quoted(names: readonly string[]): string {\n return names.length === 0 ? \"none\" : names.map((name) => `\"${name}\"`).join(\", \");\n}\n\n/** The issues of a `filter`: equality on declared fields only. The admin kit's `adminList` too. */\nexport function filterIssues(filter: unknown, fields: readonly string[]): Issues {\n if (filter === undefined) {\n return [];\n }\n if (!isRecord(filter)) {\n return [{ message: \"Expected an object of field values\", path: [\"filter\"] }];\n }\n return Object.entries(filter).flatMap(([field, value]): Issues => {\n if (!fields.includes(field)) {\n const message = `\"${field}\" is not a filter field; the filter fields are ${quoted(fields)}`;\n return [{ message, path: [\"filter\", field] }];\n }\n return isFilterValue(value)\n ? []\n : [{ message: \"Expected a string, number, boolean or null\", path: [\"filter\", field] }];\n });\n}\n\n/** The issues of a `sort`: one declared field, and a direction. The admin kit's `adminList` too. */\nexport function sortIssues(sort: unknown, fields: readonly string[]): Issues {\n if (sort === undefined) {\n return [];\n }\n if (!isRecord(sort)) {\n return [{ message: \"Expected { field, direction? }\", path: [\"sort\"] }];\n }\n const issues = unknownKeys(sort, [\"field\", \"direction\"], [\"sort\"]);\n if (typeof sort.field !== \"string\" || !fields.includes(sort.field)) {\n const message = `\"${String(sort.field)}\" is not a sort field; the sort fields are ${quoted(fields)}`;\n issues.push({ message, path: [\"sort\", \"field\"] });\n }\n if (sort.direction !== undefined && sort.direction !== \"asc\" && sort.direction !== \"desc\") {\n issues.push({ message: 'Expected \"asc\" or \"desc\"', path: [\"sort\", \"direction\"] });\n }\n return issues;\n}\n\n/** The issues of a page request's `cursor`, `limit` and `totalCount`, those it has. */\nexport function pagingIssues(value: Readonly<Record<string, unknown>>): Issues {\n const { cursor, limit, totalCount } = value;\n const issues: Issues = [];\n const isCursor =\n typeof cursor === \"string\" && cursor.length > 0 && cursor.length <= MAX_CURSOR_LENGTH;\n if (cursor !== undefined && !isCursor) {\n issues.push({ message: \"Expected a cursor from an earlier page\", path: [\"cursor\"] });\n }\n if (limit !== undefined && !(Number.isInteger(limit) && (limit as number) >= 1)) {\n issues.push({ message: \"Expected a whole number of at least 1\", path: [\"limit\"] });\n }\n if (totalCount !== undefined && typeof totalCount !== \"boolean\") {\n issues.push({ message: \"Expected a boolean\", path: [\"totalCount\"] });\n }\n return issues;\n}\n\n/** The parsed input of a valid `list` call. */\nfunction queryOf(value: Readonly<Record<string, unknown>>): ListQuery {\n const sort = value.sort as ListSort | undefined;\n const limit = (value.limit as number | undefined) ?? LIST_DEFAULT_LIMIT;\n return {\n filter: { ...(value.filter as Readonly<Record<string, FilterValue>> | undefined) },\n sort:\n sort === undefined ? undefined : { field: sort.field, direction: sort.direction ?? \"asc\" },\n cursor: value.cursor as string | undefined,\n limit: Math.min(limit, LIST_MAX_LIMIT),\n totalCount: value.totalCount === true,\n };\n}\n\n/** The entity's JSON Schema properties, which describe its filter fields; none when it cannot write them. */\nfunction entityProperties(\n entity: StandardSchemaV1 | undefined,\n target: string,\n): Readonly<Record<string, unknown>> {\n let properties: unknown;\n try {\n properties = entity === undefined ? undefined : jsonOf(entity, \"input\", target)?.properties;\n } catch {\n properties = undefined;\n }\n return isRecord(properties) ? properties : {};\n}\n\n/** The JSON Schema of one filter field: the entity's own for that field, or any plain value. */\nfunction fieldJson(properties: Readonly<Record<string, unknown>>, field: string): JsonSchema {\n const own = properties[field];\n return isRecord(own) ? { ...own } : { type: [\"string\", \"number\", \"boolean\", \"null\"] };\n}\n\n/**\n * The JSON Schema properties `filter` and `sort` of a list's input, those it\n * declares fields for. The admin kit's `adminList` too.\n */\nexport function filterSortJson(\n fields: ListFields,\n entity: StandardSchemaV1 | undefined,\n target: string,\n): Record<string, JsonSchema> {\n const properties = entityProperties(entity, target);\n const filter = Object.fromEntries(\n fields.filter.map((field) => [field, fieldJson(properties, field)]),\n );\n const sort = objectJson(\n {\n field: { type: \"string\", enum: [...fields.sort] },\n direction: { type: \"string\", enum: [\"asc\", \"desc\"] },\n },\n [\"field\"],\n );\n return {\n ...(fields.filter.length === 0 ? {} : { filter: objectJson(filter) }),\n ...(fields.sort.length === 0 ? {} : { sort }),\n };\n}\n\nfunction listJson(fields: ListFields, entity: StandardSchemaV1 | undefined, target: string) {\n return objectJson({\n ...filterSortJson(fields, entity, target),\n cursor: { type: \"string\", minLength: 1, maxLength: MAX_CURSOR_LENGTH },\n limit: { type: \"integer\", minimum: 1, maximum: LIST_MAX_LIMIT, default: LIST_DEFAULT_LIMIT },\n totalCount: { type: \"boolean\" },\n });\n}\n\n/**\n * `list`'s input: `{ filter?, sort?, cursor?, limit?, totalCount? }`, or\n * nothing. `entity` gives the filter fields' JSON Schema when it can write one.\n */\nexport function listInput<Input, Query extends ListQuery>(\n fields: ListFields,\n entity: StandardSchemaV1 | undefined,\n): KitSchema<Input, Query> {\n return kitSchema<Input, Query>(\n (input) => {\n const value = input ?? {};\n if (!isRecord(value)) {\n return { issues: [{ message: \"Expected an object\", path: [] }] };\n }\n const issues = [\n ...unknownKeys(value, [\"filter\", \"sort\", \"cursor\", \"limit\", \"totalCount\"]),\n ...filterIssues(value.filter, fields.filter),\n ...sortIssues(value.sort, fields.sort),\n ...pagingIssues(value),\n ];\n return issues.length > 0 ? { issues } : { value: queryOf(value) as Query };\n },\n { input: (target) => listJson(fields, entity, target) },\n );\n}\n\n/** The issues of a page's `items`: each must be a row with an id. */\nexport function itemsIssues(items: unknown): Issues {\n if (!Array.isArray(items)) {\n return [{ message: \"Expected an array of rows\", path: [\"items\"] }];\n }\n return items.flatMap((item: unknown, index): Issues => {\n const id = isRecord(item) ? item.id : undefined;\n return typeof id === \"string\" && id.length > 0\n ? []\n : [{ message: \"Expected a row with an id\", path: [\"items\", index] }];\n });\n}\n\n/** The JSON Schema of a page's `items`: an array of `item`'s rows, as far as `item` can describe them. */\nexport function itemsJson(item: StandardSchemaV1, target: string): JsonSchema {\n let items: JsonSchema;\n try {\n items = jsonOf(item, \"output\", target) ?? {};\n } catch {\n items = {};\n }\n return { type: \"array\", items };\n}\n\nfunction pageJson(item: StandardSchemaV1, target: string): JsonSchema {\n return objectJson(\n {\n items: itemsJson(item, target),\n nextCursor: { type: [\"string\", \"null\"] },\n totalCount: { type: \"integer\", minimum: 0 },\n },\n [\"items\", \"nextCursor\"],\n );\n}\n\n/**\n * One page of `list`: `{ items, nextCursor, totalCount? }`. Items are checked\n * to be rows with an id, not against `item`: the server strips the fields a\n * reader's level does not reach from them, which the item's own schema may\n * require.\n */\nexport function pageOutput<Item>(item: StandardSchemaV1): KitSchema<ListPage<Item>> {\n return kitSchema<ListPage<Item>>(\n (value) => {\n if (!isRecord(value)) {\n return { issues: [{ message: \"Expected a page\", path: [] }] };\n }\n const { nextCursor, totalCount } = value;\n const issues = [...unknownKeys(value, [\"items\", \"nextCursor\", \"totalCount\"])];\n issues.push(...itemsIssues(value.items));\n if (nextCursor !== null && typeof nextCursor !== \"string\") {\n issues.push({ message: \"Expected a cursor or null\", path: [\"nextCursor\"] });\n }\n if (\n totalCount !== undefined &&\n !(Number.isInteger(totalCount) && (totalCount as number) >= 0)\n ) {\n issues.push({ message: \"Expected a count of rows\", path: [\"totalCount\"] });\n }\n return issues.length > 0 ? { issues } : { value: value as unknown as ListPage<Item> };\n },\n { input: (target) => pageJson(item, target) },\n );\n}\n","// The inputs and outputs the read/write kit generates (RFC 0003 section\n// 12.1), except `list`'s (`crudList.ts`): `{ id }`, `{ ids }` (at most 200),\n// a patch with `id` added, `{ ids, data }`, a reorder's neighbors, `null`\n// and `{ count }`. A part the app's own schema provides (a create input, an\n// update patch) is validated by that schema, and its JSON Schema is the\n// app's own when its library can write one.\n\nimport type { InferInput, InferOutput, StandardSchemaV1 } from \"../standardSchema\";\nimport {\n hasJson,\n idJson,\n invalid,\n isId,\n isRecord,\n jsonOf,\n kitSchema,\n nested,\n objectJson,\n unknownKeys,\n type JsonSchema,\n type KitSchema,\n type Validated,\n} from \"./schemas\";\n\n/** The most ids one `getMany`, `bulkUpdate` or `bulkDelete` call may name. */\nexport const CRUD_MAX_IDS = 200;\n\n/** `{ id }`: one row. */\nexport interface IdInput {\n readonly id: string;\n}\n\n/** `{ ids }`: up to {@link CRUD_MAX_IDS} rows. */\nexport interface IdsInput {\n readonly ids: readonly string[];\n}\n\n/** What `bulkUpdate` and `bulkDelete` return: how many rows they changed. */\nexport interface BulkResult {\n readonly count: number;\n}\n\n/**\n * `reorder`'s input: the row to move, and the rows it lands between. `beforeId`\n * is the row that will come right before it, `afterId` the one right after;\n * one of them is enough.\n */\nexport interface ReorderInput {\n readonly id: string;\n readonly beforeId?: string;\n readonly afterId?: string;\n}\n\nfunction idsIssues(ids: unknown, path: readonly PropertyKey[]): StandardSchemaV1.Issue[] {\n if (!Array.isArray(ids)) {\n return [{ message: \"Expected an array of row ids\", path: [...path] }];\n }\n if (ids.length > CRUD_MAX_IDS) {\n return [{ message: `At most ${CRUD_MAX_IDS} ids`, path: [...path] }];\n }\n return ids.flatMap((id: unknown, index) =>\n isId(id) ? [] : [{ message: \"Expected a non-empty string\", path: [...path, index] }],\n );\n}\n\nfunction idsJson(): JsonSchema {\n return { type: \"array\", items: idJson(), maxItems: CRUD_MAX_IDS };\n}\n\n/** `{ id }`. */\nexport function idInput(): KitSchema<IdInput> {\n return kitSchema<IdInput>(\n (value) => {\n if (!isRecord(value)) {\n return invalid(\"Expected an object\");\n }\n const issues = unknownKeys(value, [\"id\"]);\n if (!isId(value.id)) {\n issues.push({ message: \"Expected a non-empty string\", path: [\"id\"] });\n }\n return issues.length > 0 ? { issues } : { value: { id: value.id as string } };\n },\n { input: () => objectJson({ id: idJson() }, [\"id\"]) },\n );\n}\n\n/** `{ ids }`, at most {@link CRUD_MAX_IDS} of them. */\nexport function idsInput(): KitSchema<IdsInput, { readonly ids: string[] }> {\n return kitSchema<IdsInput, { readonly ids: string[] }>(\n (value) => {\n if (!isRecord(value)) {\n return invalid(\"Expected an object\");\n }\n const issues = [...unknownKeys(value, [\"ids\"]), ...idsIssues(value.ids, [\"ids\"])];\n return issues.length > 0 ? { issues } : { value: { ids: [...(value.ids as string[])] } };\n },\n { input: () => objectJson({ ids: idsJson() }, [\"ids\"]) },\n );\n}\n\n/** The JSON Schema of `{ id, ...patch }`, from the patch's own object schema. */\nfunction withIdJson(patch: StandardSchemaV1, side: \"input\" | \"output\", target: string): JsonSchema {\n const json = jsonOf(patch, side, target) ?? {};\n if (json.type !== \"object\") {\n throw new Error(\"the patch schema does not describe an object\");\n }\n const properties = isRecord(json.properties) ? json.properties : {};\n const required = Array.isArray(json.required) ? (json.required as unknown[]) : [];\n return {\n ...json,\n properties: { id: idJson(), ...properties },\n required: [\"id\", ...required.filter((key) => key !== \"id\")],\n };\n}\n\n/** Validates `value` with the app's patch schema; its result must be an object. */\nasync function patchOf(\n patch: StandardSchemaV1,\n value: unknown,\n path: readonly PropertyKey[],\n): Promise<Validated<Readonly<Record<string, unknown>>>> {\n const result = await patch[\"~standard\"].validate(value);\n if (result.issues !== undefined) {\n return { issues: nested(result.issues, path) };\n }\n return isRecord(result.value)\n ? { value: result.value }\n : invalid(\"The patch schema must produce an object\", path);\n}\n\n/** The schema of `{ id } & patch`: what `update` takes. */\nexport type WithId<Patch extends StandardSchemaV1> = StandardSchemaV1<\n { readonly id: string } & InferInput<Patch>,\n { readonly id: string } & InferOutput<Patch>\n>;\n\n/**\n * `{ id, ...patch }`: `id` is checked here and the other keys by the app's\n * patch schema. With JSON Schema when the patch schema can write it.\n */\nexport function withId<Patch extends StandardSchemaV1>(patch: Patch): WithId<Patch> {\n const validate = async (\n value: unknown,\n ): Promise<Validated<Readonly<Record<string, unknown>>>> => {\n if (!isRecord(value)) {\n return invalid(\"Expected an object\");\n }\n const { id, ...rest } = value;\n const result = await patchOf(patch, rest, []);\n const issues = [\n ...(isId(id) ? [] : [{ message: \"Expected a non-empty string\", path: [\"id\"] }]),\n ...(result.issues ?? []),\n ];\n if (issues.length > 0 || result.issues !== undefined) {\n return { issues };\n }\n return { value: { ...result.value, id: id as string } };\n };\n if (!hasJson(patch)) {\n const props = { version: 1 as const, vendor: \"quickdraw\", validate };\n return Object.freeze({ \"~standard\": Object.freeze(props) }) as unknown as WithId<Patch>;\n }\n return kitSchema(validate, {\n input: (target) => withIdJson(patch, \"input\", target),\n output: (target) => withIdJson(patch, \"output\", target),\n }) as unknown as WithId<Patch>;\n}\n\n/** The schema of `{ ids, data }`: what `bulkUpdate` takes. */\nexport type BulkPatch<Patch extends StandardSchemaV1> = StandardSchemaV1<\n { readonly ids: readonly string[]; readonly data: InferInput<Patch> },\n { readonly ids: string[]; readonly data: InferOutput<Patch> }\n>;\n\nfunction bulkJson(patch: StandardSchemaV1, side: \"input\" | \"output\", target: string): JsonSchema {\n return objectJson({ ids: idsJson(), data: jsonOf(patch, side, target) ?? {} }, [\"ids\", \"data\"]);\n}\n\n/** `{ ids, data }`: up to {@link CRUD_MAX_IDS} ids, and one patch for all of them. */\nexport function bulkPatch<Patch extends StandardSchemaV1>(patch: Patch): BulkPatch<Patch> {\n const validate = async (\n value: unknown,\n ): Promise<Validated<Readonly<Record<string, unknown>>>> => {\n if (!isRecord(value)) {\n return invalid(\"Expected an object\");\n }\n const data = await patchOf(patch, value.data, [\"data\"]);\n const issues = [\n ...unknownKeys(value, [\"ids\", \"data\"]),\n ...idsIssues(value.ids, [\"ids\"]),\n ...(data.issues ?? []),\n ];\n if (issues.length > 0 || data.issues !== undefined) {\n return { issues };\n }\n return { value: { ids: [...(value.ids as string[])], data: data.value } };\n };\n if (!hasJson(patch)) {\n const props = { version: 1 as const, vendor: \"quickdraw\", validate };\n return Object.freeze({ \"~standard\": Object.freeze(props) }) as unknown as BulkPatch<Patch>;\n }\n return kitSchema(validate, {\n input: (target) => bulkJson(patch, \"input\", target),\n output: (target) => bulkJson(patch, \"output\", target),\n }) as unknown as BulkPatch<Patch>;\n}\n\nfunction neighborIssues(value: Readonly<Record<string, unknown>>): StandardSchemaV1.Issue[] {\n const { id, beforeId, afterId } = value;\n const issues: StandardSchemaV1.Issue[] = [];\n for (const key of [\"beforeId\", \"afterId\"] as const) {\n const neighbor = value[key];\n if (neighbor !== undefined && !isId(neighbor)) {\n issues.push({ message: \"Expected a non-empty string\", path: [key] });\n } else if (neighbor !== undefined && neighbor === id) {\n issues.push({ message: \"A row cannot move next to itself\", path: [key] });\n }\n }\n if (beforeId === undefined && afterId === undefined) {\n issues.push({ message: \"Give beforeId, afterId or both\", path: [] });\n } else if (beforeId !== undefined && beforeId === afterId) {\n issues.push({ message: \"beforeId and afterId must be different rows\", path: [\"afterId\"] });\n }\n return issues;\n}\n\n/** `{ id, beforeId?, afterId? }`. */\nexport function reorderInput(): KitSchema<ReorderInput> {\n return kitSchema<ReorderInput>(\n (value) => {\n if (!isRecord(value)) {\n return invalid(\"Expected an object\");\n }\n const issues = [...unknownKeys(value, [\"id\", \"beforeId\", \"afterId\"])];\n if (!isId(value.id)) {\n issues.push({ message: \"Expected a non-empty string\", path: [\"id\"] });\n }\n issues.push(...neighborIssues(value));\n if (issues.length > 0) {\n return { issues };\n }\n const { id, beforeId, afterId } = value as unknown as ReorderInput;\n return {\n value: {\n id,\n ...(beforeId === undefined ? {} : { beforeId }),\n ...(afterId === undefined ? {} : { afterId }),\n },\n };\n },\n {\n input: () => objectJson({ id: idJson(), beforeId: idJson(), afterId: idJson() }, [\"id\"]),\n },\n );\n}\n\n/** `null`: what `delete` returns. */\nexport function nullOutput(): KitSchema<null> {\n return kitSchema<null>((value) => (value === null ? { value } : invalid(\"Expected null\")), {\n input: () => ({ type: \"null\" }),\n });\n}\n\n/** `{ count }`: what `bulkUpdate` and `bulkDelete` return. */\nexport function countOutput(): KitSchema<BulkResult> {\n return kitSchema<BulkResult>(\n (value) => {\n const count = isRecord(value) ? value.count : undefined;\n return Number.isInteger(count) && (count as number) >= 0\n ? { value: { count: count as number } }\n : invalid(\"Expected { count } with a count of rows\");\n },\n { input: () => objectJson({ count: { type: \"integer\", minimum: 0 } }, [\"count\"]) },\n );\n}\n","// The admin kit's view of an entity (RFC 0003 sections 2 and 12.4): its\n// fields, read from the entity schema's Standard JSON Schema (Zod 4.2 or\n// later), since Standard Schema exposes validation only, and how a write of\n// them is checked. 4.1 read Zod's type names instead\n// (4.1 `src/server/utils/zodToAdminFields.ts:33-103`); the same field\n// types come from each property's JSON Schema here:\n//\n// | JSON Schema of the property | Admin field type |\n// |-------------------------------------------------|-----------------------|\n// | `type: \"string\"`, `format: \"date-time\"`/`\"date\"`| `date` |\n// | `enum` of strings, a string `const`, or a union | `enum` (`enumValues`) |\n// | of those | |\n// | `type: \"string\"` | `string` |\n// | `type: \"number\"` or `\"integer\"` | `number` |\n// | `type: \"boolean\"` | `boolean` |\n// | `type: \"object\"` or `\"array\"`, a union holding | `json` |\n// | one, or no type at all (`z.json()`, `{}`) | |\n// | a union of other types | `string`, as in 4.1 |\n//\n// `null` in a union or a type list makes the field nullable. A field is\n// required when the schema requires it, it is not nullable and it has no\n// default, as 4.1 counted optional, nullable and defaulted fields as not\n// required. `relation` is never derived; `fieldOverrides` sets it.\n//\n// The types here are 4.1's (4.1 `src/shared/types.ts:283-338`).\n\nimport { hasJsonSchema, type StandardSchemaV1 } from \"../standardSchema\";\nimport { isRecord, nested } from \"./schemas\";\n\n/** Supported field types for admin UI generation. */\nexport type AdminFieldType =\n | \"string\"\n | \"number\"\n | \"boolean\"\n | \"date\"\n | \"enum\"\n | \"json\"\n | \"relation\";\n\n/** Every admin field type. */\nexport const ADMIN_FIELD_TYPES: readonly AdminFieldType[] = Object.freeze([\n \"string\",\n \"number\",\n \"boolean\",\n \"date\",\n \"enum\",\n \"json\",\n \"relation\",\n]);\n\n/** Configuration for a single field in the admin UI: derived from the entity schema, with overrides. */\nexport interface AdminFieldConfig {\n /** Field name (property key on the entity). */\n readonly name: string;\n /** Field type for rendering the right input. */\n readonly type: AdminFieldType;\n /** Human-readable label. */\n readonly label: string;\n /** Whether the field is required for creation. */\n readonly required: boolean;\n /** Whether `adminCreate` and `adminUpdate` may write it (never `id` or the timestamps). */\n readonly editable: boolean;\n /** Whether to show the field as a table column. */\n readonly showInTable: boolean;\n /** Whether `adminList` may sort by it: the contract declares it in `sort`. */\n readonly sortable: boolean;\n /**\n * Whether `adminList` may filter on it: the contract declares it in\n * `filter`. `adminMeta` always says; optional (default `false`) so field\n * configurations written for 4.x, which had no `filterable`, still type.\n */\n readonly filterable?: boolean;\n /** For enum fields, the allowed values. */\n readonly enumValues?: readonly string[];\n /** For relation fields, the related service's name. */\n readonly relationService?: string;\n /**\n * What the field holds, when the kit knows it: `\"grants\"` for a user's\n * service-wide grants (`serviceAccess`, or the column the server's\n * `auth.serviceAccessSource` names, whatever its name), which\n * `admin.handlers(contract, { grants: true })` shows. An admin screen with\n * a grants editor of its own finds that field by it, never by its name.\n * Absent for any other field.\n */\n readonly kind?: \"grants\";\n /**\n * Whether a generic create or edit form shows the field. `false` from a\n * `fieldOverrides` entry (`{ serviceAccess: { showInForm: false } }`) keeps\n * it for an editor of the app's own; the kit still reads and writes it.\n * Absent unless overridden: shown.\n */\n readonly showInForm?: boolean;\n}\n\n/** Service metadata for admin UI generation: what `adminMeta` returns. */\nexport interface AdminServiceMeta {\n /** The service's name on the wire (`\"taskService\"`). */\n readonly serviceName: string;\n /** Human-readable display name (`\"Tasks\"`). */\n readonly displayName: string;\n /** The entity's fields, but those the service hides, as configured for an admin screen. */\n readonly fields: readonly AdminFieldConfig[];\n}\n\n/** An admin field type the entity schema can give: every type but `relation`. */\nexport type EntityFieldType = Exclude<AdminFieldType, \"relation\">;\n\n/** One field of the entity, as its JSON Schema describes it. */\nexport interface AdminEntityField {\n readonly name: string;\n readonly type: EntityFieldType;\n /** Required, not nullable and without a default. */\n readonly required: boolean;\n /** Whether the field accepts `null`. */\n readonly nullable: boolean;\n /** The values of an `enum` field. */\n readonly enumValues: readonly string[] | undefined;\n}\n\n/**\n * Fields no admin call writes, whatever the service configures: the row's key\n * and its timestamps, which the database sets (4.1's non-editable fields,\n * 4.1 `src/server/utils/zodToAdminFields.ts:7`).\n */\nexport const ADMIN_NEVER_WRITABLE: readonly string[] = Object.freeze([\n \"id\",\n \"createdAt\",\n \"updatedAt\",\n \"created_at\",\n \"updated_at\",\n]);\n\n/** The JSON Schema target fields are read from: the MCP bridge's. */\nconst TARGET = \"draft-07\";\n\n/** How deep `$ref`s are followed before a property counts as JSON. */\nconst MAX_REFS = 8;\n\ntype Node = Readonly<Record<string, unknown>>;\n\n/** The `definitions` and `$defs` of the entity's JSON Schema, which `$ref`s point into. */\ntype Defs = Readonly<Record<string, unknown>>;\n\n/** What one property's JSON Schema says: its type, whether it takes `null`, and its enum values. */\ninterface Shape {\n readonly type: EntityFieldType;\n readonly nullable: boolean;\n readonly enumValues?: readonly string[];\n}\n\nconst JSON_SHAPE: Shape = Object.freeze({ type: \"json\", nullable: true });\n\n/** `node` with its `$ref` followed, or `undefined` for a node that says nothing (`true`, a dangling ref). */\nfunction resolve(node: unknown, defs: Defs, depth = 0): Node | undefined {\n if (!isRecord(node)) {\n return undefined;\n }\n const ref = node.$ref;\n if (typeof ref !== \"string\") {\n return node;\n }\n const match = /^#\\/(definitions|\\$defs)\\/(.+)$/.exec(ref);\n const group = match === null ? undefined : defs[match[1] ?? \"\"];\n const target = isRecord(group) ? group[match?.[2] ?? \"\"] : undefined;\n return depth < MAX_REFS ? resolve(target, defs, depth + 1) : undefined;\n}\n\nfunction isNullNode(node: Node | undefined): boolean {\n if (node === undefined) {\n return false;\n }\n const values = node.enum;\n return (\n node.type === \"null\" ||\n (Object.hasOwn(node, \"const\") && node.const === null) ||\n (Array.isArray(values) && values.length > 0 && values.every((value) => value === null))\n );\n}\n\n/** A string `type` alone: `format` makes a string a date. */\nfunction typeShape(type: unknown, format: unknown): EntityFieldType {\n switch (type) {\n case \"string\":\n return format === \"date-time\" || format === \"date\" ? \"date\" : \"string\";\n case \"number\":\n case \"integer\":\n return \"number\";\n case \"boolean\":\n return \"boolean\";\n default:\n return \"json\";\n }\n}\n\n/** The shape of a `const`. */\nfunction constShape(value: unknown): Shape {\n if (typeof value === \"string\") {\n return { type: \"enum\", nullable: false, enumValues: [value] };\n }\n return { type: typeShape(typeof value, undefined), nullable: value === null };\n}\n\n/** The shape of an `enum`: of strings an `enum` field, otherwise its type. */\nfunction enumShape(values: readonly unknown[], node: Node): Shape {\n const present = values.filter((value) => value !== null);\n const nullable = present.length < values.length;\n if (present.length > 0 && present.every((value) => typeof value === \"string\")) {\n return { type: \"enum\", nullable, enumValues: present as string[] };\n }\n const type = typeof node.type === \"string\" ? node.type : typeof present[0];\n return { type: typeShape(type, undefined), nullable };\n}\n\n/** The shape of several types at once: JSON when one is a structure, else a string (4.1's default). */\nfunction mixedShape(shapes: readonly Shape[], nullable: boolean): Shape {\n if (shapes.some((shape) => shape.type === \"json\")) {\n return { type: \"json\", nullable };\n }\n if (shapes.every((shape) => shape.type === \"enum\")) {\n const values = shapes.flatMap((shape) => shape.enumValues ?? []);\n return { type: \"enum\", nullable, enumValues: [...new Set(values)] };\n }\n return { type: \"string\", nullable };\n}\n\n/** The shape of a `type` list, `[\"string\", \"null\"]`. */\nfunction typesShape(types: readonly unknown[], node: Node): Shape {\n const present = types.filter((type) => type !== \"null\");\n const nullable = present.length < types.length;\n if (present.length === 1) {\n return { type: typeShape(present[0], node.format), nullable };\n }\n return mixedShape(\n present.map((type) => ({ type: typeShape(type, undefined), nullable: false })),\n nullable,\n );\n}\n\nfunction shapeOf(node: unknown, defs: Defs, depth = 0): Shape {\n const resolved = resolve(node, defs);\n if (resolved === undefined || depth > MAX_REFS) {\n return JSON_SHAPE;\n }\n const union = resolved.anyOf ?? resolved.oneOf;\n if (Array.isArray(union)) {\n return unionShape(union, defs, depth);\n }\n if (Object.hasOwn(resolved, \"const\")) {\n return constShape(resolved.const);\n }\n if (Array.isArray(resolved.enum)) {\n return enumShape(resolved.enum, resolved);\n }\n if (Array.isArray(resolved.type)) {\n return typesShape(resolved.type, resolved);\n }\n if (resolved.type === undefined) {\n // No type at all (`z.unknown()`, `z.any()`): any JSON value, null among them.\n return JSON_SHAPE;\n }\n return {\n type: typeShape(resolved.type, resolved.format),\n nullable: resolved.type === \"null\",\n };\n}\n\n/** The shape of `anyOf` or `oneOf`: `null` makes it nullable, one other member is the field. */\nfunction unionShape(members: readonly unknown[], defs: Defs, depth: number): Shape {\n const present = members.filter((member) => !isNullNode(resolve(member, defs)));\n const nullable = present.length < members.length;\n const shapes = present.map((member) => shapeOf(member, defs, depth + 1));\n if (shapes.length === 1 && shapes[0] !== undefined) {\n return { ...shapes[0], nullable: nullable || shapes[0].nullable };\n }\n return mixedShape(shapes, nullable || shapes.some((shape) => shape.nullable));\n}\n\n/** The object schema a JSON Schema document describes, following one top-level `$ref`. */\nfunction rootObject(json: Node): Node | undefined {\n const root = resolve(json, { definitions: json.definitions, $defs: json.$defs });\n return isRecord(root?.properties) ? root : undefined;\n}\n\n/** Fails with why the entity schema cannot list the admin kit's fields, as a sentence. */\nexport type FieldsFailure = (message: string) => never;\n\n/** The entity's input JSON Schema (draft-07, as the MCP bridge reads it), or a failure naming why it has none. */\nfunction entityJson(entity: StandardSchemaV1, fail: FieldsFailure): Node {\n if (!hasJsonSchema(entity)) {\n fail(\n \"the entity schema cannot describe itself as JSON Schema, which the admin kit's field metadata needs: use Zod 4.2 or later for that schema\",\n );\n }\n try {\n const json: unknown = entity[\"~standard\"].jsonSchema.input({ target: TARGET });\n if (isRecord(json)) {\n return json;\n }\n return fail(\"the entity schema's JSON Schema is not an object\");\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n return fail(\n `the entity schema cannot be written as JSON Schema (${reason}), which the admin kit's field metadata needs: change that schema`,\n );\n }\n}\n\n/**\n * The entity's fields, in its schema's order, from its Standard JSON Schema.\n * Fails through `fail` for a schema that cannot describe itself, or that does\n * not describe an object with an `id`.\n */\nexport function entityFieldsOf(\n entity: StandardSchemaV1,\n fail: FieldsFailure,\n): readonly AdminEntityField[] {\n const json = entityJson(entity, fail);\n const root = rootObject(json);\n const properties = root?.properties;\n if (root === undefined || !isRecord(properties) || !Object.hasOwn(properties, \"id\")) {\n fail(\"the entity schema must describe an object with an id\");\n }\n const required = new Set(Array.isArray(root.required) ? root.required : []);\n const defs: Defs = { definitions: json.definitions, $defs: json.$defs };\n return Object.freeze(\n Object.entries(properties).map(([name, node]) => {\n const shape = shapeOf(node, defs);\n const defaulted = isRecord(node) && Object.hasOwn(node, \"default\");\n return Object.freeze({\n name,\n type: shape.type,\n required: required.has(name) && !shape.nullable && !defaulted,\n nullable: shape.nullable,\n enumValues:\n shape.enumValues === undefined ? undefined : Object.freeze([...shape.enumValues]),\n });\n }),\n );\n}\n\ntype Issues = StandardSchemaV1.Issue[];\n\n/** The first key of an issue's path. */\nfunction headOf(issue: StandardSchemaV1.Issue): PropertyKey | undefined {\n const [head] = issue.path ?? [];\n return typeof head === \"object\" ? head.key : head;\n}\n\nfunction quoted(names: readonly string[]): string {\n return names.length === 0 ? \"none\" : names.map((name) => `\"${name}\"`).join(\", \");\n}\n\n/**\n * The issues of a write's `data` at `path`: a key that is not one of\n * `writable` (the entity's fields but `id` and the timestamps), and a value\n * the entity schema refuses for its field. The entity schema checks the given\n * fields only: a field the write leaves out is the database's to fill.\n */\nexport async function dataIssues(\n entity: StandardSchemaV1,\n writable: readonly string[],\n data: unknown,\n path: readonly PropertyKey[],\n): Promise<Issues> {\n if (!isRecord(data)) {\n return [{ message: \"Expected an object of field values\", path: [...path] }];\n }\n const given = Object.keys(data).filter((key) => data[key] !== undefined);\n const refused = given.filter((key) => !writable.includes(key));\n if (refused.length > 0) {\n return refused.map((key) => ({\n message: ADMIN_NEVER_WRITABLE.includes(key)\n ? `\"${key}\" is not writable`\n : `\"${key}\" is not a writable field; the writable fields are ${quoted(writable)}`,\n path: [...path, key],\n }));\n }\n if (given.length === 0) {\n return [];\n }\n const result = await entity[\"~standard\"].validate(writtenData(data));\n const issues = (result.issues ?? []).filter((issue) => {\n const head = headOf(issue);\n return typeof head === \"string\" && given.includes(head);\n });\n return nested(issues, path);\n}\n\n/** The fields a write sets: `data` without its `undefined` values. */\nexport function writtenData(data: Readonly<Record<string, unknown>>): Record<string, unknown> {\n return Object.fromEntries(Object.entries(data).filter(([, value]) => value !== undefined));\n}\n","// The inputs and outputs the admin kit generates (RFC 0003 section 12.4).\n//\n// `adminList` pages by number, as 4.1's did\n// (4.1 `src/server/BaseService.ts:1367-1388`): `page` from 1, `pageSize`\n// 20 by default and at most 100 (a larger one is clamped). Its filter and\n// sort are restricted to the fields the contract declares and checked as\n// the read/write kit's `list` checks them (`crudList.ts`): a filter is\n// equality on plain values, so nothing the caller sends reaches the database\n// as an operator. 4.1 handed the caller's `where` and `orderBy` to the\n// database as they came.\n//\n// A write's `data` holds field values of the entity: a key that is not one of\n// its fields, `id` and the timestamps are refused, and each value is checked\n// by the entity schema itself (`adminFields.ts`). A row out is the entity's\n// row, checked to have an id: the server leaves out the fields the caller's\n// level does not reach and those the service hides.\n\nimport type { AccessLevel } from \"../access\";\nimport type { SortDirection } from \"../collections\";\nimport type { StandardSchemaV1 } from \"../standardSchema\";\nimport { ADMIN_FIELD_TYPES, dataIssues, writtenData, type AdminServiceMeta } from \"./adminFields\";\nimport {\n filterIssues,\n filterSortJson,\n itemsIssues,\n sortIssues,\n type FilterValue,\n type ListFields,\n type ListSort,\n} from \"./crudList\";\nimport {\n idJson,\n invalid,\n isId,\n isRecord,\n jsonOf,\n kitSchema,\n objectJson,\n unknownKeys,\n type JsonSchema,\n type KitSchema,\n} from \"./schemas\";\n\n/** `adminList`'s page size when the caller gives none: 4.1's. */\nexport const ADMIN_DEFAULT_PAGE_SIZE = 20;\n\n/** The largest page `adminList` returns: a larger `pageSize` is clamped to it. */\nexport const ADMIN_MAX_PAGE_SIZE = 100;\n\n/** The highest page number `adminList` takes: past it the offset alone is a slow scan. */\nexport const ADMIN_MAX_PAGE = 1_000_000;\n\n/** What an `adminList` call passes: a page, and a filter and a sort over the declared fields. */\nexport type AdminListInput<Row, Filter extends string, Sort extends string> = {\n /** The page, from 1. Default 1. */\n readonly page?: number;\n /** The rows per page: default 20, at most 100 (a larger one is clamped). */\n readonly pageSize?: number;\n readonly filter?: [Filter] extends [never]\n ? undefined\n : { readonly [Field in Filter]?: Field extends keyof Row ? Row[Field] : never };\n readonly sort?: [Sort] extends [never] ? undefined : ListSort<Sort>;\n};\n\n/** `adminList`'s input as its handler receives it: defaults applied, the page size clamped. */\nexport interface AdminListQuery<Filter extends string = string, Sort extends string = string> {\n readonly page: number;\n /** At least 1 and at most {@link ADMIN_MAX_PAGE_SIZE}. */\n readonly pageSize: number;\n /** Equality per declared field; `{}` for none. */\n readonly filter: { readonly [Field in Filter]?: FilterValue };\n /** The caller's sort, or `undefined` for the default order. */\n readonly sort: { readonly field: Sort; readonly direction: SortDirection } | undefined;\n}\n\n/** One page of `adminList`, as 4.1's `AdminListResponse`. */\nexport interface AdminPage<Item> {\n readonly items: Item[];\n /** Every row the filter matches. */\n readonly total: number;\n readonly page: number;\n readonly pageSize: number;\n /** `ceil(total / pageSize)`. */\n readonly totalPages: number;\n}\n\n/** The fields no admin write sets: the row's key and its timestamps. */\nexport type AdminNeverWritable = \"id\" | \"createdAt\" | \"updatedAt\" | \"created_at\" | \"updated_at\";\n\n/** The fields an admin write sets without `editable`: any of the entity's fields but `id` and the timestamps. */\nexport type AdminWritable<Row> = Exclude<keyof Row, AdminNeverWritable>;\n\n/**\n * The field values an admin write may set: those of `Field`, the fields\n * `admin.contract({ editable })` names, else any of the entity's fields but\n * `id` and the timestamps.\n */\nexport type AdminData<Row, Field extends PropertyKey = AdminWritable<Row>> = {\n readonly [Name in Field & keyof Row]?: Row[Name];\n};\n\n/** `adminCreate`: the new row's field values. */\nexport interface AdminCreateInput<Row, Field extends PropertyKey = AdminWritable<Row>> {\n readonly data: AdminData<Row, Field>;\n}\n\n/** `adminUpdate`: the row, and the field values to change. */\nexport interface AdminUpdateInput<Row, Field extends PropertyKey = AdminWritable<Row>> {\n readonly id: string;\n readonly data: AdminData<Row, Field>;\n}\n\n/** `adminCreate`'s input as its handler receives it: `data` without `undefined` values. */\nexport interface AdminCreateQuery {\n readonly data: Readonly<Record<string, unknown>>;\n}\n\n/** `adminUpdate`'s input as its handler receives it. */\nexport interface AdminUpdateQuery {\n readonly id: string;\n readonly data: Readonly<Record<string, unknown>>;\n}\n\n/** `adminMeta` takes nothing: no input, or `{}`. */\nexport type AdminMetaInput = Readonly<Record<string, never>>;\n\n/** A level a subscriber holds a row at: one entity room per level (RFC 0003 section 6). */\nexport type SubscriberLevel = Exclude<AccessLevel, \"Public\">;\n\n/** What `adminSubscribers` and `adminReemit` return: the sockets subscribed to one row. */\nexport interface AdminSubscribers {\n readonly id: string;\n /** Sockets subscribed to the row, at every level. */\n readonly count: number;\n /** The same per level: the sockets in each of the row's tier rooms. */\n readonly levels: { readonly [Level in SubscriberLevel]: number };\n /**\n * `true` when the counts cover every server. Behind a cluster adapter\n * (Redis) a server sees only its own sockets, and this is `false`.\n */\n readonly complete: boolean;\n}\n\ntype Issues = StandardSchemaV1.Issue[];\n\ntype UnknownRecord = Readonly<Record<string, unknown>>;\n\nconst LEVELS: readonly SubscriberLevel[] = Object.freeze([\"Read\", \"Moderate\", \"Admin\"]);\n\nfunction isCount(value: unknown, minimum = 0): boolean {\n return Number.isInteger(value) && (value as number) >= minimum;\n}\n\nfunction pageIssues(value: UnknownRecord): Issues {\n const { page, pageSize } = value;\n const issues: Issues = [];\n if (page !== undefined && !(isCount(page, 1) && (page as number) <= ADMIN_MAX_PAGE)) {\n issues.push({ message: `Expected a page number from 1 to ${ADMIN_MAX_PAGE}`, path: [\"page\"] });\n }\n if (pageSize !== undefined && !isCount(pageSize, 1)) {\n issues.push({ message: \"Expected a whole number of at least 1\", path: [\"pageSize\"] });\n }\n return issues;\n}\n\n/** The parsed input of a valid `adminList` call. */\nfunction listQueryOf(value: UnknownRecord): AdminListQuery {\n const sort = value.sort as ListSort | undefined;\n const pageSize = (value.pageSize as number | undefined) ?? ADMIN_DEFAULT_PAGE_SIZE;\n return {\n page: (value.page as number | undefined) ?? 1,\n pageSize: Math.min(pageSize, ADMIN_MAX_PAGE_SIZE),\n filter: { ...(value.filter as Readonly<Record<string, FilterValue>> | undefined) },\n sort:\n sort === undefined ? undefined : { field: sort.field, direction: sort.direction ?? \"asc\" },\n };\n}\n\n/**\n * `adminList`'s input: `{ page?, pageSize?, filter?, sort? }`, or nothing.\n * `entity` gives the filter fields' JSON Schema.\n */\nexport function adminListInput<Input, Query extends AdminListQuery>(\n fields: ListFields,\n entity: StandardSchemaV1,\n): KitSchema<Input, Query> {\n return kitSchema<Input, Query>(\n (input) => {\n const value = input ?? {};\n if (!isRecord(value)) {\n return invalid(\"Expected an object\");\n }\n const issues = [\n ...unknownKeys(value, [\"page\", \"pageSize\", \"filter\", \"sort\"]),\n ...filterIssues(value.filter, fields.filter),\n ...sortIssues(value.sort, fields.sort),\n ...pageIssues(value),\n ];\n return issues.length > 0 ? { issues } : { value: listQueryOf(value) as Query };\n },\n {\n input: (target) =>\n objectJson({\n ...filterSortJson(fields, entity, target),\n page: { type: \"integer\", minimum: 1, maximum: ADMIN_MAX_PAGE, default: 1 },\n pageSize: {\n type: \"integer\",\n minimum: 1,\n maximum: ADMIN_MAX_PAGE_SIZE,\n default: ADMIN_DEFAULT_PAGE_SIZE,\n },\n }),\n },\n );\n}\n\n/** The entity's JSON Schema, or nothing when it cannot be written for `target`. */\nfunction entityJson(\n entity: StandardSchemaV1,\n side: \"input\" | \"output\",\n target: string,\n): JsonSchema {\n try {\n return jsonOf(entity, side, target) ?? {};\n } catch {\n return {};\n }\n}\n\n/**\n * The entity's row as JSON Schema, apart from the definitions its `$ref`s\n * point into, which the document holding it carries at its root. Nothing is\n * required: the server leaves out fields the caller may not see.\n */\nfunction rowJson(entity: StandardSchemaV1, target: string): { row: JsonSchema; defs: JsonSchema } {\n const { definitions, $defs, required: _required, ...row } = entityJson(entity, \"output\", target);\n return {\n row,\n defs: {\n ...(definitions === undefined ? {} : { definitions }),\n ...($defs === undefined ? {} : { $defs }),\n },\n };\n}\n\n/** The JSON Schema of a write's `data`: the writable fields' own schemas, none required. */\nfunction dataJson(\n entity: StandardSchemaV1,\n writable: readonly string[],\n target: string,\n): { data: JsonSchema; defs: JsonSchema } {\n const json = entityJson(entity, \"input\", target);\n const properties = isRecord(json.properties) ? json.properties : {};\n const fields = writable\n .filter((name) => Object.hasOwn(properties, name))\n .map((name) => [name, properties[name] as JsonSchema]);\n const { definitions, $defs } = json;\n return {\n data: objectJson(Object.fromEntries(fields) as Record<string, JsonSchema>),\n defs: {\n ...(definitions === undefined ? {} : { definitions }),\n ...($defs === undefined ? {} : { $defs }),\n },\n };\n}\n\n/** A write's input: `{ data }`, with `id` too for an update. */\nfunction writeInput<Input, Parsed>(\n entity: StandardSchemaV1,\n writable: readonly string[],\n withId: boolean,\n): KitSchema<Input, Parsed> {\n const keys = withId ? [\"id\", \"data\"] : [\"data\"];\n return kitSchema<Input, Parsed>(\n async (input) => {\n if (!isRecord(input)) {\n return invalid(withId ? \"Expected { id, data }\" : \"Expected { data }\");\n }\n const issues = [...unknownKeys(input, keys)];\n if (withId && !isId(input.id)) {\n issues.push({ message: \"Expected a non-empty string\", path: [\"id\"] });\n }\n issues.push(...(await dataIssues(entity, writable, input.data, [\"data\"])));\n if (issues.length > 0) {\n return { issues };\n }\n const data = writtenData(input.data as UnknownRecord);\n return { value: (withId ? { id: input.id, data } : { data }) as Parsed };\n },\n {\n input: (target) => {\n const { data, defs } = dataJson(entity, writable, target);\n const properties: Record<string, JsonSchema> = withId ? { id: idJson(), data } : { data };\n return { ...objectJson(properties, keys), ...defs };\n },\n },\n );\n}\n\n/** `adminCreate`'s input: `{ data }`, the new row's values of `writable` fields. */\nexport function adminCreateInput<Row, Field extends PropertyKey = AdminWritable<Row>>(\n entity: StandardSchemaV1,\n writable: readonly string[],\n): KitSchema<AdminCreateInput<Row, Field>, AdminCreateQuery> {\n return writeInput(entity, writable, false);\n}\n\n/** `adminUpdate`'s input: `{ id, data }`, the values of `writable` fields to change. */\nexport function adminUpdateInput<Row, Field extends PropertyKey = AdminWritable<Row>>(\n entity: StandardSchemaV1,\n writable: readonly string[],\n): KitSchema<AdminUpdateInput<Row, Field>, AdminUpdateQuery> {\n return writeInput(entity, writable, true);\n}\n\nfunction rowIssues(value: unknown): Issues {\n return isRecord(value) && isId(value.id)\n ? []\n : [{ message: \"Expected a row with an id\", path: [] }];\n}\n\n/** One row of the entity, as `adminGet`, `adminCreate` and `adminUpdate` return it. */\nexport function adminRowOutput<Row>(entity: StandardSchemaV1): KitSchema<Row> {\n return kitSchema<Row>(\n (value) => {\n const issues = rowIssues(value);\n return issues.length > 0 ? { issues } : { value: value as Row };\n },\n {\n input: (target) => {\n const { row, defs } = rowJson(entity, target);\n return { ...row, ...defs };\n },\n },\n );\n}\n\nfunction pageCountIssues(value: UnknownRecord): Issues {\n const minimums: readonly [string, number][] = [\n [\"total\", 0],\n [\"page\", 1],\n [\"pageSize\", 1],\n [\"totalPages\", 0],\n ];\n return minimums.flatMap(([key, minimum]) =>\n isCount(value[key], minimum)\n ? []\n : [{ message: `Expected a count of at least ${minimum}`, path: [key] }],\n );\n}\n\n/** One page of `adminList`: `{ items, total, page, pageSize, totalPages }`. */\nexport function adminPageOutput<Item>(entity: StandardSchemaV1): KitSchema<AdminPage<Item>> {\n return kitSchema<AdminPage<Item>>(\n (value) => {\n if (!isRecord(value)) {\n return invalid(\"Expected a page\");\n }\n const issues = [\n ...unknownKeys(value, [\"items\", \"total\", \"page\", \"pageSize\", \"totalPages\"]),\n ...itemsIssues(value.items),\n ...pageCountIssues(value),\n ];\n return issues.length > 0 ? { issues } : { value: value as unknown as AdminPage<Item> };\n },\n {\n input: (target) => {\n const { row, defs } = rowJson(entity, target);\n const count = (minimum: number): JsonSchema => ({ type: \"integer\", minimum });\n return {\n ...objectJson(\n {\n items: { type: \"array\", items: row },\n total: count(0),\n page: count(1),\n pageSize: { type: \"integer\", minimum: 1, maximum: ADMIN_MAX_PAGE_SIZE },\n totalPages: count(0),\n },\n [\"items\", \"total\", \"page\", \"pageSize\", \"totalPages\"],\n ),\n ...defs,\n };\n },\n },\n );\n}\n\n/** `adminMeta`'s input: nothing, or `{}`. */\nexport function adminMetaInput(): KitSchema<AdminMetaInput | undefined, undefined> {\n return kitSchema<AdminMetaInput | undefined, undefined>(\n (input) => {\n if (input === undefined) {\n return { value: undefined };\n }\n if (!isRecord(input)) {\n return invalid(\"Expected nothing, or {}\");\n }\n const issues = unknownKeys(input, []);\n return issues.length > 0 ? { issues } : { value: undefined };\n },\n { input: () => objectJson({}) },\n );\n}\n\nconst STRING: JsonSchema = Object.freeze({ type: \"string\" });\nconst BOOLEAN: JsonSchema = Object.freeze({ type: \"boolean\" });\n\nfunction fieldConfigJson(): JsonSchema {\n return objectJson(\n {\n name: STRING,\n type: { type: \"string\", enum: [...ADMIN_FIELD_TYPES] },\n label: STRING,\n required: BOOLEAN,\n editable: BOOLEAN,\n showInTable: BOOLEAN,\n sortable: BOOLEAN,\n filterable: BOOLEAN,\n enumValues: { type: \"array\", items: STRING },\n relationService: STRING,\n kind: { type: \"string\", enum: [\"grants\"] },\n showInForm: BOOLEAN,\n },\n [\"name\", \"type\", \"label\", \"required\", \"editable\", \"showInTable\", \"sortable\"],\n );\n}\n\nfunction fieldIssues(fields: unknown): Issues {\n if (!Array.isArray(fields)) {\n return [{ message: \"Expected an array of fields\", path: [\"fields\"] }];\n }\n return fields.flatMap((field: unknown, index): Issues => {\n const valid =\n isRecord(field) &&\n typeof field.name === \"string\" &&\n ADMIN_FIELD_TYPES.some((type) => type === field.type);\n return valid ? [] : [{ message: \"Expected a field's configuration\", path: [\"fields\", index] }];\n });\n}\n\n/** `adminMeta`'s output: the service's name, display name and field configurations. */\nexport function adminMetaOutput(): KitSchema<AdminServiceMeta> {\n return kitSchema<AdminServiceMeta>(\n (value) => {\n if (!isRecord(value)) {\n return invalid(\"Expected { serviceName, displayName, fields }\");\n }\n const issues = [...unknownKeys(value, [\"serviceName\", \"displayName\", \"fields\"])];\n for (const key of [\"serviceName\", \"displayName\"]) {\n if (typeof value[key] !== \"string\") {\n issues.push({ message: \"Expected a string\", path: [key] });\n }\n }\n issues.push(...fieldIssues(value.fields));\n return issues.length > 0 ? { issues } : { value: value as unknown as AdminServiceMeta };\n },\n {\n input: () =>\n objectJson(\n {\n serviceName: STRING,\n displayName: STRING,\n fields: { type: \"array\", items: fieldConfigJson() },\n },\n [\"serviceName\", \"displayName\", \"fields\"],\n ),\n },\n );\n}\n\nfunction levelsIssues(levels: unknown): Issues {\n const valid =\n isRecord(levels) &&\n Object.keys(levels).length === LEVELS.length &&\n LEVELS.every((level) => isCount(levels[level]));\n return valid ? [] : [{ message: \"Expected a count per level\", path: [\"levels\"] }];\n}\n\n/** What `adminSubscribers` and `adminReemit` return: `{ id, count, levels, complete }`. */\nexport function adminSubscribersOutput(): KitSchema<AdminSubscribers> {\n return kitSchema<AdminSubscribers>(\n (value) => {\n if (!isRecord(value)) {\n return invalid(\"Expected { id, count, levels, complete }\");\n }\n const issues = [\n ...unknownKeys(value, [\"id\", \"count\", \"levels\", \"complete\"]),\n ...(isId(value.id) ? [] : [{ message: \"Expected a row id\", path: [\"id\"] }]),\n ...(isCount(value.count) ? [] : [{ message: \"Expected a count\", path: [\"count\"] }]),\n ...levelsIssues(value.levels),\n ...(typeof value.complete === \"boolean\"\n ? []\n : [{ message: \"Expected a boolean\", path: [\"complete\"] }]),\n ];\n return issues.length > 0 ? { issues } : { value: value as unknown as AdminSubscribers };\n },\n {\n input: () =>\n objectJson(\n {\n id: idJson(),\n count: { type: \"integer\", minimum: 0 },\n levels: objectJson(\n Object.fromEntries(LEVELS.map((level) => [level, { type: \"integer\", minimum: 0 }])),\n LEVELS,\n ),\n complete: BOOLEAN,\n },\n [\"id\", \"count\", \"levels\", \"complete\"],\n ),\n },\n );\n}\n","// The admin kit's contract half (RFC 0003 section 12.4). `admin.contract`\n// returns ordinary `query` and `mutation` entries to spread into a\n// contract's `methods`: the back-office methods 4.1's `installAdminMethods`\n// registered outside the type map (4.1 `src/server/BaseService.ts:1185-1333`),\n// so every app called them through untyped hooks:\n//\n// export const task = defineContract(\"taskService\", {\n// entity: taskSchema,\n// methods: {\n// ...admin.contract({ entity: taskSchema, filter: [\"status\"], sort: [\"createdAt\", \"title\"] }),\n// rename: mutation({ ... }),\n// },\n// });\n//\n// `adminList` pages every row by page number; `adminGet`, `adminCreate`,\n// `adminUpdate` and `adminDelete` read and write one row; `adminMeta`\n// describes the entity's fields for an admin screen; `adminSubscribers`\n// counts the sockets subscribed to a row and `adminReemit` sends it to them\n// again. `expose` picks the methods to add; all eight without it. `editable`\n// (finding R1.4 of the 5.0.0 review) names the only fields `adminCreate` and\n// `adminUpdate` take, in their checks, their JSON Schema (and so the MCP\n// tools made from it) and their types; without it they take every field but\n// `id` and the timestamps. The entity schema must describe itself as JSON\n// Schema (Zod 4.2 or later): the fields come from it, so `admin.contract`\n// refuses a schema that cannot.\n//\n// The server half (`admin.handlers` on `./server`) finds the kit's entries in\n// the contract by what they were made for (`adminSpecOf`), its types by their\n// tag (`AdminTag`), and the client adds `qd.<service>.admin`, every admin\n// method's member in one place.\n\nimport type { AnyContract, RowSchema } from \"../defineContract\";\nimport type { MethodName } from \"../infer\";\nimport { mutation, query, type MethodDef, type MutationDef, type QueryDef } from \"../methods\";\nimport { isStandardSchema, type InferOutput, type StandardSchemaV1 } from \"../standardSchema\";\nimport {\n ADMIN_NEVER_WRITABLE,\n entityFieldsOf,\n type AdminEntityField,\n type AdminServiceMeta,\n} from \"./adminFields\";\nimport {\n adminCreateInput,\n adminListInput,\n adminMetaInput,\n adminMetaOutput,\n adminPageOutput,\n adminRowOutput,\n adminSubscribersOutput,\n adminUpdateInput,\n type AdminCreateInput,\n type AdminCreateQuery,\n type AdminListInput,\n type AdminListQuery,\n type AdminMetaInput,\n type AdminPage,\n type AdminSubscribers,\n type AdminUpdateInput,\n type AdminUpdateQuery,\n type AdminWritable,\n} from \"./adminSchemas\";\nimport type { ScalarFieldOf } from \"./crud\";\nimport { idInput, nullOutput, type IdInput } from \"./crudSchemas\";\nimport type { KitSchema } from \"./schemas\";\n\n/** The methods the admin kit can add. */\nexport type AdminMethodName =\n | \"adminList\"\n | \"adminGet\"\n | \"adminCreate\"\n | \"adminUpdate\"\n | \"adminDelete\"\n | \"adminMeta\"\n | \"adminSubscribers\"\n | \"adminReemit\";\n\n/** Every method of the admin kit, in the order `expose` defaults to. */\nexport const ADMIN_METHODS: readonly AdminMethodName[] = Object.freeze([\n \"adminList\",\n \"adminGet\",\n \"adminCreate\",\n \"adminUpdate\",\n \"adminDelete\",\n \"adminMeta\",\n \"adminSubscribers\",\n \"adminReemit\",\n]);\n\n/** Type-only: marks a method the admin kit made, and which one. Never set. */\nexport interface AdminTag<Kind extends AdminMethodName> {\n readonly \"~admin\"?: Kind;\n}\n\n/** The names of a contract's methods the admin kit made. */\nexport type AdminMethodsOf<C extends AnyContract> = {\n [M in MethodName<C>]: \"~admin\" extends keyof C[\"methods\"][M] ? M : never;\n}[MethodName<C>];\n\n/** `admin.contract`'s options. */\nexport interface AdminContractOptions {\n /** The contract's entity schema, which must describe itself as JSON Schema (Zod 4.2 or later). */\n readonly entity: RowSchema;\n /** The fields `adminList` may filter on, by equality. */\n readonly filter?: readonly string[];\n /** The fields `adminList` may sort by; the first is the default order (else `id`). */\n readonly sort?: readonly string[];\n /**\n * The only fields `adminCreate` and `adminUpdate` take (never `id` or a\n * timestamp): their input checks, JSON Schema and types name just these,\n * and the server half writes just these. Without it, every field but `id`\n * and the timestamps. `admin.handlers` given a list too must give the same.\n */\n readonly editable?: readonly string[];\n /** The methods to add; all eight when absent. */\n readonly expose?: readonly AdminMethodName[];\n /** Descriptions for people and agents, per method; the kit's own for the rest. */\n readonly describe?: { readonly [Name in AdminMethodName]?: string };\n}\n\ntype RowOf<Entity> = Entity extends StandardSchemaV1 ? InferOutput<Entity> : never;\n\ntype Quoted<Names> = `\"${Names & string}\"`;\n\ntype FieldsIn<O, Key extends \"filter\" | \"sort\" | \"editable\"> = O extends {\n readonly [K in Key]: readonly (infer Field extends string)[];\n}\n ? Field\n : never;\n\n/** A broken option becomes a message: replacing the whole option keeps TypeScript from printing `never`. */\ntype Problem<Option extends \"filter\" | \"sort\", Wrong> = [Wrong] extends [never]\n ? unknown\n : {\n readonly [K in Option]: `admin.contract: ${Option}: ${Quoted<Wrong>} is not a field of the entity holding strings, numbers or booleans`;\n };\n\n/** `editable` naming a field the kit never writes, as a message. */\ntype EditableProblem<Wrong> = [Wrong] extends [never]\n ? unknown\n : {\n readonly editable: `admin.contract: editable: ${Quoted<Wrong>} is not a field of the entity the kit may write`;\n };\n\n/** The check of `filter`, `sort` and `editable` against the entity that the option types alone cannot state. */\ntype AdminChecks<O> = O extends { readonly entity: infer Entity }\n ? Problem<\"filter\", Exclude<FieldsIn<O, \"filter\">, ScalarFieldOf<RowOf<Entity>>>> &\n Problem<\"sort\", Exclude<FieldsIn<O, \"sort\">, ScalarFieldOf<RowOf<Entity>>>> &\n EditableProblem<Exclude<FieldsIn<O, \"editable\">, AdminWritable<RowOf<Entity>>>>\n : unknown;\n\nexport type AdminListDef<Row, Filter extends string, Sort extends string> = QueryDef<\n KitSchema<AdminListInput<Row, Filter, Sort> | undefined, AdminListQuery<Filter, Sort>>,\n KitSchema<AdminPage<Row>>\n> &\n AdminTag<\"adminList\">;\nexport type AdminGetDef<Row> = QueryDef<KitSchema<IdInput>, KitSchema<Row>> & AdminTag<\"adminGet\">;\nexport type AdminCreateDef<Row, Field extends PropertyKey = AdminWritable<Row>> = MutationDef<\n KitSchema<AdminCreateInput<Row, Field>, AdminCreateQuery>,\n KitSchema<Row>\n> &\n AdminTag<\"adminCreate\">;\nexport type AdminUpdateDef<Row, Field extends PropertyKey = AdminWritable<Row>> = MutationDef<\n KitSchema<AdminUpdateInput<Row, Field>, AdminUpdateQuery>,\n KitSchema<Row>\n> &\n AdminTag<\"adminUpdate\">;\nexport type AdminDeleteDef = MutationDef<KitSchema<IdInput>, KitSchema<null>> &\n AdminTag<\"adminDelete\">;\nexport type AdminMetaDef = QueryDef<\n KitSchema<AdminMetaInput | undefined, undefined>,\n KitSchema<AdminServiceMeta>\n> &\n AdminTag<\"adminMeta\">;\nexport type AdminSubscribersDef = QueryDef<KitSchema<IdInput>, KitSchema<AdminSubscribers>> &\n AdminTag<\"adminSubscribers\">;\nexport type AdminReemitDef = MutationDef<KitSchema<IdInput>, KitSchema<AdminSubscribers>> &\n AdminTag<\"adminReemit\">;\n\ntype EntityRowIn<O> = O extends { readonly entity: infer Entity } ? RowOf<Entity> : never;\n\n/** The fields the writes take: those `editable` names, else every field but `id` and the timestamps. */\ntype EditableIn<O> = O extends { readonly editable: readonly (infer Field extends string)[] }\n ? Field\n : AdminWritable<EntityRowIn<O>>;\n\ntype AdminDefOf<O, Name extends AdminMethodName> = {\n adminList: AdminListDef<EntityRowIn<O>, FieldsIn<O, \"filter\">, FieldsIn<O, \"sort\">>;\n adminGet: AdminGetDef<EntityRowIn<O>>;\n adminCreate: AdminCreateDef<EntityRowIn<O>, EditableIn<O>>;\n adminUpdate: AdminUpdateDef<EntityRowIn<O>, EditableIn<O>>;\n adminDelete: AdminDeleteDef;\n adminMeta: AdminMetaDef;\n adminSubscribers: AdminSubscribersDef;\n adminReemit: AdminReemitDef;\n}[Name];\n\ntype ExposedIn<O> = O extends { readonly expose: readonly (infer Name extends AdminMethodName)[] }\n ? Name\n : AdminMethodName;\n\n/** The entries `admin.contract(options)` returns: one per method it adds. */\nexport type AdminMethods<O> = { readonly [Name in ExposedIn<O>]: AdminDefOf<O, Name> };\n\n/** What the server half and the client need to know about a method the admin kit made. */\nexport interface AdminSpec {\n readonly method: AdminMethodName;\n /** The entity schema the kit was made for: the contract's own, which the server half checks. */\n readonly entity: RowSchema;\n /** The fields `adminList` may filter on. */\n readonly filter: readonly string[];\n /** The fields `adminList` may sort by. */\n readonly sort: readonly string[];\n /** The entity's fields, from its JSON Schema, in its order. */\n readonly fields: readonly AdminEntityField[];\n /** The only fields the writes take, as `editable` named them; `undefined` without it. */\n readonly editable: readonly string[] | undefined;\n}\n\nconst SPECS = new WeakMap<object, AdminSpec>();\n\n/** What the admin kit made `method` for, or `undefined` for any other method. */\nexport function adminSpecOf(method: unknown): AdminSpec | undefined {\n return typeof method === \"object\" && method !== null ? SPECS.get(method) : undefined;\n}\n\nconst DESCRIBE: Readonly<Record<AdminMethodName, string>> = Object.freeze({\n adminList:\n \"Lists every row for a service administrator, a page at a time (page numbers from 1, at most 100 rows a page), filtered and sorted by the declared fields.\",\n adminGet: \"Reads one row by id, as a service administrator sees it.\",\n adminCreate:\n \"Creates a row from data, the new row's field values; the database sets its id and timestamps.\",\n adminUpdate: \"Changes the given fields of one row; its id and timestamps cannot be changed.\",\n adminDelete: \"Deletes one row.\",\n adminMeta:\n \"Describes the service's fields for an admin screen: their types, labels, and which can be edited, sorted and filtered.\",\n adminSubscribers: \"Counts the sockets subscribed to one row, per access level.\",\n adminReemit: \"Sends one row as it is now to every socket subscribed to it.\",\n});\n\ntype UnknownRecord = Readonly<Record<string, unknown>>;\n\nconst OPTIONS = [\"entity\", \"filter\", \"sort\", \"editable\", \"expose\", \"describe\"];\n\nfunction isRecord(value: unknown): value is UnknownRecord {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction fail(message: string): never {\n throw new TypeError(`admin.contract: ${message}`);\n}\n\nfunction quoted(names: readonly string[]): string {\n return names.map((name) => `\"${name}\"`).join(\", \");\n}\n\nfunction checkOptions(options: unknown): UnknownRecord & { readonly entity: RowSchema } {\n if (!isRecord(options)) {\n fail(\"options must be { entity, filter?, sort?, editable?, expose?, describe? }\");\n }\n const unknownKey = Object.keys(options).find((key) => !OPTIONS.includes(key));\n if (unknownKey !== undefined) {\n fail(`unknown option \"${unknownKey}\"; the options are ${OPTIONS.join(\", \")}`);\n }\n if (!isStandardSchema(options.entity)) {\n fail(\"entity must be the contract's entity schema\");\n }\n return options as UnknownRecord & { readonly entity: RowSchema };\n}\n\n/** `filter` or `sort`: distinct fields of the entity holding strings, numbers or booleans. */\nfunction checkFields(\n owner: \"filter\" | \"sort\",\n names: unknown,\n fields: readonly AdminEntityField[],\n): readonly string[] {\n if (names === undefined) {\n return Object.freeze([]);\n }\n const valid =\n Array.isArray(names) &&\n names.every((name) => typeof name === \"string\") &&\n new Set(names).size === names.length;\n if (!valid) {\n fail(`${owner} must be a list of distinct field names`);\n }\n for (const name of names as string[]) {\n const field = fields.find((candidate) => candidate.name === name);\n if (field === undefined || field.type === \"json\") {\n fail(`${owner}: \"${name}\" is not a field of the entity holding strings, numbers or booleans`);\n }\n }\n return Object.freeze([...(names as string[])]);\n}\n\n/** `editable`: distinct fields of the entity the kit may write, or `undefined` without it. */\nfunction checkEditable(\n names: unknown,\n fields: readonly AdminEntityField[],\n): readonly string[] | undefined {\n if (names === undefined) {\n return undefined;\n }\n const valid =\n Array.isArray(names) &&\n names.every((name) => typeof name === \"string\") &&\n new Set(names).size === names.length;\n if (!valid) {\n fail(\"editable must be a list of distinct field names\");\n }\n for (const name of names as string[]) {\n if (ADMIN_NEVER_WRITABLE.includes(name)) {\n fail(`editable: \"${name}\" is never editable; the database sets it`);\n }\n if (!fields.some((field) => field.name === name)) {\n fail(`editable: \"${name}\" is not a field of the entity`);\n }\n }\n return Object.freeze([...(names as string[])]);\n}\n\n/** The methods the options add: those `expose` names, or all of them. */\nfunction exposedOf(expose: unknown): readonly AdminMethodName[] {\n if (expose === undefined) {\n return ADMIN_METHODS;\n }\n const valid =\n Array.isArray(expose) &&\n expose.length > 0 &&\n expose.every((name) => ADMIN_METHODS.some((known) => known === name)) &&\n new Set(expose).size === expose.length;\n if (!valid) {\n fail(`expose must name one or more distinct admin methods: ${quoted(ADMIN_METHODS)}`);\n }\n return expose as AdminMethodName[];\n}\n\n/** The descriptions the options give, each for a method they add. */\nfunction describedOf(names: readonly AdminMethodName[], describe: unknown): UnknownRecord {\n if (describe === undefined) {\n return {};\n }\n if (!isRecord(describe)) {\n fail(\"describe must map method names to descriptions\");\n }\n for (const [name, text] of Object.entries(describe)) {\n if (!names.some((added) => added === name)) {\n fail(`describe names \"${name}\", which these options do not add`);\n }\n if (typeof text !== \"string\" || text.length === 0) {\n fail(`describe for \"${name}\" must be a non-empty string`);\n }\n }\n return describe;\n}\n\n/** What every entry is made from: the entity, its fields, and the declared filter and sort fields. */\ntype SpecBase = Omit<AdminSpec, \"method\">;\n\n/** The entry of one admin method; `writable` are the fields its writes may set. */\nfunction build(\n name: AdminMethodName,\n base: SpecBase,\n writable: readonly string[],\n describe: string,\n): MethodDef {\n const { entity } = base;\n switch (name) {\n case \"adminList\":\n return query({\n input: adminListInput(base, entity),\n output: adminPageOutput(entity),\n describe,\n });\n case \"adminGet\":\n return query({ input: idInput(), output: adminRowOutput(entity), describe });\n case \"adminCreate\":\n return mutation({\n input: adminCreateInput(entity, writable),\n output: adminRowOutput(entity),\n describe,\n });\n case \"adminUpdate\":\n return mutation({\n input: adminUpdateInput(entity, writable),\n output: adminRowOutput(entity),\n describe,\n });\n case \"adminDelete\":\n return mutation({ input: idInput(), output: nullOutput(), describe });\n case \"adminMeta\":\n return query({ input: adminMetaInput(), output: adminMetaOutput(), describe });\n case \"adminSubscribers\":\n return query({ input: idInput(), output: adminSubscribersOutput(), describe });\n default:\n return mutation({ input: idInput(), output: adminSubscribersOutput(), describe });\n }\n}\n\nfunction contract<const O extends AdminContractOptions>(\n options: O & NoInfer<AdminChecks<O>>,\n): AdminMethods<O> {\n const checked = checkOptions(options);\n const { entity } = checked;\n const fields = entityFieldsOf(entity, fail);\n const editable = checkEditable(checked.editable, fields);\n const base: SpecBase = Object.freeze({\n entity,\n filter: checkFields(\"filter\", checked.filter, fields),\n sort: checkFields(\"sort\", checked.sort, fields),\n fields,\n editable,\n });\n const names = exposedOf(checked.expose);\n const described = describedOf(names, checked.describe);\n const writable =\n editable ??\n fields.map((field) => field.name).filter((field) => !ADMIN_NEVER_WRITABLE.includes(field));\n const methods: Record<string, MethodDef> = {};\n for (const name of names) {\n const own = described[name];\n const def = build(name, base, writable, typeof own === \"string\" ? own : DESCRIBE[name]);\n SPECS.set(def, Object.freeze({ ...base, method: name }));\n methods[name] = def;\n }\n return Object.freeze(methods) as unknown as AdminMethods<O>;\n}\n\n/**\n * The admin kit's contract half: `admin.contract({ entity, filter?, sort?,\n * editable?, expose?, describe? })` makes the admin methods, which the server half\n * (`admin.handlers` on `./server`) implements, each open to a service-wide\n * `Admin` grant unless the service says otherwise.\n */\nexport const admin = Object.freeze({ contract });\n\nexport type {\n AdminEntityField,\n AdminFieldConfig,\n AdminFieldType,\n AdminServiceMeta,\n EntityFieldType,\n} from \"./adminFields\";\n"],"mappings":"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","names":["nullable","fail","quoted","entityJson","withId","isRecord","quoted"]}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// src/server/auth/validateOrigin.ts
|
|
2
|
+
var OAUTH_RETURN_ORIGIN_COOKIE = "oauth_return_origin";
|
|
3
|
+
var LOCALHOST_REGEX = /^http:\/\/localhost:\d+$/;
|
|
4
|
+
function envExtraOrigins() {
|
|
5
|
+
const raw = process.env.EXTRA_ALLOWED_ORIGINS;
|
|
6
|
+
if (!raw) return [];
|
|
7
|
+
return raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
8
|
+
}
|
|
9
|
+
function validateRedirectOrigin(origin, options = {}) {
|
|
10
|
+
if (!origin) return null;
|
|
11
|
+
const clientUrl = options.clientUrl ?? process.env.CLIENT_URL;
|
|
12
|
+
let parsedOrigin;
|
|
13
|
+
try {
|
|
14
|
+
parsedOrigin = new URL(origin);
|
|
15
|
+
} catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const cleanOrigin = parsedOrigin.origin;
|
|
19
|
+
if (clientUrl && cleanOrigin === clientUrl) {
|
|
20
|
+
return cleanOrigin;
|
|
21
|
+
}
|
|
22
|
+
const extra = options.extraAllowedOrigins ?? envExtraOrigins();
|
|
23
|
+
if (extra.includes(cleanOrigin)) {
|
|
24
|
+
return cleanOrigin;
|
|
25
|
+
}
|
|
26
|
+
if (options.allowedPatterns?.some((pattern) => pattern.test(cleanOrigin))) {
|
|
27
|
+
return cleanOrigin;
|
|
28
|
+
}
|
|
29
|
+
if ((options.allowLocalhostInDev ?? true) && process.env.NODE_ENV !== "production" && LOCALHOST_REGEX.test(cleanOrigin)) {
|
|
30
|
+
return cleanOrigin;
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/server/auth/routes/origins.ts
|
|
36
|
+
function exactOrigin(entry, owner) {
|
|
37
|
+
let url;
|
|
38
|
+
try {
|
|
39
|
+
url = typeof entry === "string" ? new URL(entry) : void 0;
|
|
40
|
+
} catch {
|
|
41
|
+
url = void 0;
|
|
42
|
+
}
|
|
43
|
+
const bare = url !== void 0 && (url.protocol === "https:" || url.protocol === "http:") && url.username === "" && url.password === "" && url.pathname === "/" && url.search === "" && url.hash === "";
|
|
44
|
+
if (url === void 0 || !bare) {
|
|
45
|
+
throw new TypeError(
|
|
46
|
+
`${owner}: allowedOrigins entries are origins such as "https://app.example.com" or anchored patterns; got ${String(entry)}`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return url.origin;
|
|
50
|
+
}
|
|
51
|
+
function anchoredPattern(pattern, owner) {
|
|
52
|
+
const { source } = pattern;
|
|
53
|
+
const anchored = source.startsWith("^") && source.endsWith("$") && !source.endsWith("\\$");
|
|
54
|
+
if (!anchored || pattern.global || pattern.sticky) {
|
|
55
|
+
throw new TypeError(
|
|
56
|
+
`${owner}: an allowedOrigins pattern must match whole origins, anchored with ^ and $ and without the g or y flag; got ${String(pattern)}`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return new RegExp(`^(?:${source})$`, pattern.flags);
|
|
60
|
+
}
|
|
61
|
+
function originAllowlist(allowedOrigins, owner, allowEmpty = false) {
|
|
62
|
+
if (!Array.isArray(allowedOrigins) || allowedOrigins.length === 0 && !allowEmpty) {
|
|
63
|
+
throw new TypeError(`${owner}: allowedOrigins must list the web app's origins`);
|
|
64
|
+
}
|
|
65
|
+
const exact = [];
|
|
66
|
+
const patterns = [];
|
|
67
|
+
for (const entry of allowedOrigins) {
|
|
68
|
+
if (entry instanceof RegExp) {
|
|
69
|
+
patterns.push(anchoredPattern(entry, owner));
|
|
70
|
+
} else {
|
|
71
|
+
exact.push(exactOrigin(entry, owner));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const options = {
|
|
75
|
+
// An empty client URL, not undefined: undefined falls back to process.env.CLIENT_URL.
|
|
76
|
+
clientUrl: "",
|
|
77
|
+
extraAllowedOrigins: exact,
|
|
78
|
+
allowedPatterns: patterns,
|
|
79
|
+
allowLocalhostInDev: false
|
|
80
|
+
};
|
|
81
|
+
return Object.freeze({
|
|
82
|
+
allowed: (value) => typeof value === "string" && value !== "" ? validateRedirectOrigin(value, options) : null,
|
|
83
|
+
fallback: exact[0]
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
var ROUTE_ORIGINS = /* @__PURE__ */ new WeakMap();
|
|
87
|
+
function rememberRouteOrigins(sessions, origins) {
|
|
88
|
+
ROUTE_ORIGINS.set(sessions, origins);
|
|
89
|
+
}
|
|
90
|
+
function routeOriginsOf(sessions) {
|
|
91
|
+
return ROUTE_ORIGINS.get(sessions);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export {
|
|
95
|
+
OAUTH_RETURN_ORIGIN_COOKIE,
|
|
96
|
+
validateRedirectOrigin,
|
|
97
|
+
originAllowlist,
|
|
98
|
+
rememberRouteOrigins,
|
|
99
|
+
routeOriginsOf
|
|
100
|
+
};
|
|
101
|
+
//# sourceMappingURL=chunk-NO4M6PO5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server/auth/validateOrigin.ts","../src/server/auth/routes/origins.ts"],"sourcesContent":["/**\n * Origin validation utility for OAuth redirect and CORS security.\n *\n * An origin is allowed when it is the client URL, one of the extra origins\n * or matches an app's pattern, or, outside production, is localhost. GitHub\n * Codespaces origins (`*.app.github.dev`) are never allowed by default since\n * 5.0.1 (finding R1.2 of the 5.0.0 review): anyone can open a Codespace, so\n * the allowance let any such page open a socket or finish a sign-in as a\n * signed-in user in production, wherever an app used this helper for CORS or\n * a cookie check. An app that wants one lists a pattern in `allowedPatterns`.\n */\n\nexport const OAUTH_RETURN_ORIGIN_COOKIE = \"oauth_return_origin\";\n\nexport interface ValidateOriginOptions {\n /**\n * The primary web client origin. Defaults to process.env.CLIENT_URL.\n */\n clientUrl?: string;\n /**\n * Additional exact-match origins. Defaults to the comma-separated\n * process.env.EXTRA_ALLOWED_ORIGINS. Lets a single API back multiple web\n * hosts (e.g. prod + staging).\n */\n extraAllowedOrigins?: string[];\n /**\n * App-specific origin patterns (e.g. preview-deploy subdomains).\n */\n allowedPatterns?: RegExp[];\n /**\n * Ignored: kept so 5.0.0 code that passes it still compiles.\n *\n * @deprecated Codespaces origins are never allowed since 5.0.1; list a pattern in allowedPatterns if one is wanted.\n */\n allowCodespaces?: boolean;\n /**\n * Allow http://localhost:* when NODE_ENV !== \"production\". Default: true.\n */\n allowLocalhostInDev?: boolean;\n}\n\nconst LOCALHOST_REGEX = /^http:\\/\\/localhost:\\d+$/;\n\nfunction envExtraOrigins(): string[] {\n const raw = process.env.EXTRA_ALLOWED_ORIGINS;\n if (!raw) return [];\n return raw\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n}\n\n/**\n * Validates if an origin is safe for OAuth redirect / CORS.\n *\n * Only the origin (scheme + host + port) is compared, never the path, to\n * prevent path-injection bypasses.\n *\n * @param origin - The origin to validate\n * @param options - Override env-derived defaults\n * @returns The validated origin if allowed, null otherwise\n */\nexport function validateRedirectOrigin(\n origin: string,\n options: ValidateOriginOptions = {},\n): string | null {\n if (!origin) return null;\n\n const clientUrl = options.clientUrl ?? process.env.CLIENT_URL;\n\n let parsedOrigin: URL;\n try {\n parsedOrigin = new URL(origin);\n } catch {\n return null;\n }\n\n const cleanOrigin = parsedOrigin.origin;\n\n if (clientUrl && cleanOrigin === clientUrl) {\n return cleanOrigin;\n }\n\n const extra = options.extraAllowedOrigins ?? envExtraOrigins();\n if (extra.includes(cleanOrigin)) {\n return cleanOrigin;\n }\n\n if (options.allowedPatterns?.some((pattern) => pattern.test(cleanOrigin))) {\n return cleanOrigin;\n }\n\n if (\n (options.allowLocalhostInDev ?? true) &&\n process.env.NODE_ENV !== \"production\" &&\n LOCALHOST_REGEX.test(cleanOrigin)\n ) {\n return cleanOrigin;\n }\n\n return null;\n}\n","// The browser origins the auth kit trusts (RFC 0003 section 12.6): where a\n// sign-in may return to, and which pages may open a socket with the session\n// cookie. One list serves both. `validateRedirectOrigin` decides, with each\n// of its defaults turned off: no CLIENT_URL or EXTRA_ALLOWED_ORIGINS from the\n// environment, no implicit localhost (it allows no GitHub Codespaces origin\n// at all). The list the app passes is the whole allowlist.\n\nimport { validateRedirectOrigin, type ValidateOriginOptions } from \"../validateOrigin\";\n\n/**\n * An allowed origin: exact (`\"https://app.example.com\"`), or a pattern over\n * whole origins, anchored at both ends\n * (`/^https:\\/\\/[a-z0-9-]+\\.preview\\.example\\.com$/`).\n */\nexport type AllowedOrigin = string | RegExp;\n\n/** The allowlist, checked and normalized. */\nexport interface OriginAllowlist {\n /** The origin of `value` (an origin or a URL) when it is allowed, else `null`. */\n allowed(value: string | undefined): string | null;\n /** The first exact origin listed: where a sign-in returns when it names none. */\n readonly fallback: string | undefined;\n}\n\nfunction exactOrigin(entry: unknown, owner: string): string {\n let url: URL | undefined;\n try {\n url = typeof entry === \"string\" ? new URL(entry) : undefined;\n } catch {\n url = undefined;\n }\n const bare =\n url !== undefined &&\n (url.protocol === \"https:\" || url.protocol === \"http:\") &&\n url.username === \"\" &&\n url.password === \"\" &&\n url.pathname === \"/\" &&\n url.search === \"\" &&\n url.hash === \"\";\n if (url === undefined || !bare) {\n throw new TypeError(\n `${owner}: allowedOrigins entries are origins such as \"https://app.example.com\" or anchored patterns; got ${String(entry)}`,\n );\n }\n return url.origin;\n}\n\n/**\n * The pattern, refused unless it is written anchored with `^` and `$`, and\n * compiled to match whole origins whatever it holds: `^a|b$` is anchored\n * only at its ends (`^a` or `b$`), so `/^https:\\/\\/app|staging\\.example\\.com$/`\n * would allow `https://app.attacker.net`. The source is wrapped as\n * `^(?:source)$`, so every alternative must match the whole origin.\n */\nfunction anchoredPattern(pattern: RegExp, owner: string): RegExp {\n const { source } = pattern;\n const anchored = source.startsWith(\"^\") && source.endsWith(\"$\") && !source.endsWith(\"\\\\$\");\n if (!anchored || pattern.global || pattern.sticky) {\n throw new TypeError(\n `${owner}: an allowedOrigins pattern must match whole origins, anchored with ^ and $ and without the g or y flag; got ${String(pattern)}`,\n );\n }\n return new RegExp(`^(?:${source})$`, pattern.flags);\n}\n\n/**\n * Checks and normalizes an allowlist; throws a `TypeError` naming `owner`\n * for an entry that is neither an origin nor an anchored pattern, or for an\n * empty list unless `allowEmpty`.\n */\nexport function originAllowlist(\n allowedOrigins: readonly AllowedOrigin[],\n owner: string,\n allowEmpty = false,\n): OriginAllowlist {\n if (!Array.isArray(allowedOrigins) || (allowedOrigins.length === 0 && !allowEmpty)) {\n throw new TypeError(`${owner}: allowedOrigins must list the web app's origins`);\n }\n const exact: string[] = [];\n const patterns: RegExp[] = [];\n for (const entry of allowedOrigins) {\n if (entry instanceof RegExp) {\n patterns.push(anchoredPattern(entry, owner));\n } else {\n exact.push(exactOrigin(entry, owner));\n }\n }\n const options: ValidateOriginOptions = {\n // An empty client URL, not undefined: undefined falls back to process.env.CLIENT_URL.\n clientUrl: \"\",\n extraAllowedOrigins: exact,\n allowedPatterns: patterns,\n allowLocalhostInDev: false,\n };\n return Object.freeze({\n allowed: (value: string | undefined) =>\n typeof value === \"string\" && value !== \"\" ? validateRedirectOrigin(value, options) : null,\n fallback: exact[0],\n });\n}\n\n/**\n * The allowlist each `createAuthRoutes` was given, by the session store it\n * writes to: `requireSession` over the same store applies it when it is given\n * no `allowedOrigins` of its own.\n */\nconst ROUTE_ORIGINS = new WeakMap<object, OriginAllowlist>();\n\n/** Remembers the allowlist of the auth routes that write sessions to `sessions`. */\nexport function rememberRouteOrigins(sessions: object, origins: OriginAllowlist): void {\n ROUTE_ORIGINS.set(sessions, origins);\n}\n\n/** The allowlist of the auth routes that write sessions to `sessions`, if any were made. */\nexport function routeOriginsOf(sessions: object): OriginAllowlist | undefined {\n return ROUTE_ORIGINS.get(sessions);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -63,6 +63,8 @@ function callHandler(req, res, _next, options) {
|
|
|
63
63
|
if (!res.getHeader("Retry-After")) {
|
|
64
64
|
res.setHeader("Retry-After", String(Math.ceil(retryAfterMs / 1e3)));
|
|
65
65
|
}
|
|
66
|
+
res.setHeader("Cache-Control", "no-store");
|
|
67
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
66
68
|
res.status(options.statusCode).json({
|
|
67
69
|
ok: false,
|
|
68
70
|
e: { code: "RATE_LIMITED", message: "Rate limit exceeded", data: { retryAfterMs } }
|
|
@@ -87,4 +89,4 @@ export {
|
|
|
87
89
|
createPublicApiLimiter,
|
|
88
90
|
createCallLimiter
|
|
89
91
|
};
|
|
90
|
-
//# sourceMappingURL=chunk-
|
|
92
|
+
//# sourceMappingURL=chunk-NW6U45HX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server/express/rateLimit.ts"],"sourcesContent":["/**\n * Express rate-limit presets built on express-rate-limit.\n *\n * Lives in the dedicated `/server/express` subpath so the core `/server`\n * entry point carries no express-rate-limit dependency. All presets are\n * factories (not module-level singletons) so env/config is read at call time.\n *\n * Note: distinct from the Socket.IO `createRateLimiter` exported from\n * `/server` — these protect REST routes (OAuth, webhooks, public APIs).\n */\n\nimport type { NextFunction, Request, Response } from \"express\";\nimport {\n ipKeyGenerator,\n rateLimit,\n type Options,\n type RateLimitRequestHandler,\n} from \"express-rate-limit\";\n\ntype PartialOptions = Partial<Options>;\n\nfunction handler(_req: Request, res: Response, _next: NextFunction, options: Options): void {\n const retryAfterSec = Math.max(1, Math.ceil((options.windowMs ?? 60_000) / 1000));\n if (!res.getHeader(\"Retry-After\")) {\n res.setHeader(\"Retry-After\", String(retryAfterSec));\n }\n res.status(options.statusCode ?? 429).json({ error: \"Rate limit exceeded\" });\n}\n\nconst jsonLimiter: PartialOptions = {\n standardHeaders: true,\n legacyHeaders: false,\n handler,\n};\n\n/** Normalize IPv4-mapped IPv6 addresses (::ffff:1.2.3.4 → 1.2.3.4). */\nexport function stripIp(raw: string | undefined): string {\n const ip = raw ?? \"unknown\";\n return ip.startsWith(\"::ffff:\") ? ip.slice(7) : ip;\n}\n\n/**\n * Key by Bearer token when present, falling back to client IP. Lets\n * token-authenticated clients get their own bucket instead of sharing\n * a NAT'd IP. Nothing here checks the token (the 5.1 audit's\n * TRANSPORT-4): a caller that sends a new made-up token on each request\n * gets a fresh bucket each time, even behind `requireSession`, which signs\n * a request in by its cookie first and never reads the bearer token then.\n * Key a limiter mounted behind `requireSession` by the user it verified\n * instead (`keyGenerator: (req) => sessionOf(req).userId`), and anonymous\n * traffic by IP, as `createPublicApiLimiter` does.\n */\nexport function bearerOrIp(req: Request): string {\n const auth = req.headers.authorization ?? \"\";\n if (auth.startsWith(\"Bearer \")) return auth.slice(7);\n return ipKeyGenerator(stripIp(req.ip));\n}\n\n/**\n * Base factory: JSON 429 body + Retry-After header + standard headers.\n */\nexport function createJsonRateLimiter(options: PartialOptions): RateLimitRequestHandler {\n return rateLimit({ ...jsonLimiter, ...options });\n}\n\n/** OAuth flows: 20 requests / 15 min per IP (status sub-routes excluded). */\nexport function createAuthLimiter(overrides: PartialOptions = {}): RateLimitRequestHandler {\n return createJsonRateLimiter({\n windowMs: 15 * 60 * 1000,\n max: 20,\n skip: (req) => req.path.endsWith(\"/status\"),\n ...overrides,\n });\n}\n\n/** Auth status polling: 120 requests / 15 min per IP. */\nexport function createAuthStatusLimiter(overrides: PartialOptions = {}): RateLimitRequestHandler {\n return createJsonRateLimiter({\n windowMs: 15 * 60 * 1000,\n max: 120,\n ...overrides,\n });\n}\n\n/** Inbound webhooks: 300 requests / min per IP. */\nexport function createWebhookLimiter(overrides: PartialOptions = {}): RateLimitRequestHandler {\n return createJsonRateLimiter({\n windowMs: 60 * 1000,\n max: 300,\n ...overrides,\n });\n}\n\n/** Generic public API: 60 requests / min per IP. */\nexport function createPublicApiLimiter(overrides: PartialOptions = {}): RateLimitRequestHandler {\n return createJsonRateLimiter({\n windowMs: 60 * 1000,\n max: 60,\n ...overrides,\n });\n}\n\n/**\n * Answers a refused call in the HTTP transport's own reply shape, so a\n * server caller (`createServerCaller`) reports `RATE_LIMITED` with\n * `retryAfterMs` instead of an unreadable reply, with the headers of every\n * `/qd` reply (`no-store`, `nosniff`).\n */\nfunction callHandler(req: Request, res: Response, _next: NextFunction, options: Options): void {\n const info = (req as Request & Partial<Record<string, { resetTime?: Date }>>)[\n options.requestPropertyName\n ];\n const untilReset =\n info?.resetTime === undefined ? options.windowMs : info.resetTime.getTime() - Date.now();\n const retryAfterMs = Math.max(1000, untilReset);\n if (!res.getHeader(\"Retry-After\")) {\n res.setHeader(\"Retry-After\", String(Math.ceil(retryAfterMs / 1000)));\n }\n res.setHeader(\"Cache-Control\", \"no-store\");\n res.setHeader(\"X-Content-Type-Options\", \"nosniff\");\n res.status(options.statusCode).json({\n ok: false,\n e: { code: \"RATE_LIMITED\", message: \"Rate limit exceeded\", data: { retryAfterMs } },\n });\n}\n\n/**\n * Calls through the HTTP transport (RFC 0003 section 10), mounted with\n * `createServer({ http: { rateLimit: createCallLimiter() } })`: 300 calls per\n * minute per IP, refused with `429 { ok: false, e: { code: \"RATE_LIMITED\",\n * message, data: { retryAfterMs } } }`. Server-side prefetch reaches the API\n * from the web server's address, so key it some other way (`keyGenerator`)\n * or raise `max` when the web server prefetches for many users; never by\n * an unverified bearer token (`bearerOrIp`).\n */\nexport function createCallLimiter(overrides: PartialOptions = {}): RateLimitRequestHandler {\n return createJsonRateLimiter({\n windowMs: 60 * 1000,\n max: 300,\n handler: callHandler,\n ...overrides,\n });\n}\n"],"mappings":";AAYA;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAIP,SAAS,QAAQ,MAAe,KAAe,OAAqB,SAAwB;AAC1F,QAAM,gBAAgB,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,YAAY,OAAU,GAAI,CAAC;AAChF,MAAI,CAAC,IAAI,UAAU,aAAa,GAAG;AACjC,QAAI,UAAU,eAAe,OAAO,aAAa,CAAC;AAAA,EACpD;AACA,MAAI,OAAO,QAAQ,cAAc,GAAG,EAAE,KAAK,EAAE,OAAO,sBAAsB,CAAC;AAC7E;AAEA,IAAM,cAA8B;AAAA,EAClC,iBAAiB;AAAA,EACjB,eAAe;AAAA,EACf;AACF;AAGO,SAAS,QAAQ,KAAiC;AACvD,QAAM,KAAK,OAAO;AAClB,SAAO,GAAG,WAAW,SAAS,IAAI,GAAG,MAAM,CAAC,IAAI;AAClD;AAaO,SAAS,WAAW,KAAsB;AAC/C,QAAM,OAAO,IAAI,QAAQ,iBAAiB;AAC1C,MAAI,KAAK,WAAW,SAAS,EAAG,QAAO,KAAK,MAAM,CAAC;AACnD,SAAO,eAAe,QAAQ,IAAI,EAAE,CAAC;AACvC;AAKO,SAAS,sBAAsB,SAAkD;AACtF,SAAO,UAAU,EAAE,GAAG,aAAa,GAAG,QAAQ,CAAC;AACjD;AAGO,SAAS,kBAAkB,YAA4B,CAAC,GAA4B;AACzF,SAAO,sBAAsB;AAAA,IAC3B,UAAU,KAAK,KAAK;AAAA,IACpB,KAAK;AAAA,IACL,MAAM,CAAC,QAAQ,IAAI,KAAK,SAAS,SAAS;AAAA,IAC1C,GAAG;AAAA,EACL,CAAC;AACH;AAGO,SAAS,wBAAwB,YAA4B,CAAC,GAA4B;AAC/F,SAAO,sBAAsB;AAAA,IAC3B,UAAU,KAAK,KAAK;AAAA,IACpB,KAAK;AAAA,IACL,GAAG;AAAA,EACL,CAAC;AACH;AAGO,SAAS,qBAAqB,YAA4B,CAAC,GAA4B;AAC5F,SAAO,sBAAsB;AAAA,IAC3B,UAAU,KAAK;AAAA,IACf,KAAK;AAAA,IACL,GAAG;AAAA,EACL,CAAC;AACH;AAGO,SAAS,uBAAuB,YAA4B,CAAC,GAA4B;AAC9F,SAAO,sBAAsB;AAAA,IAC3B,UAAU,KAAK;AAAA,IACf,KAAK;AAAA,IACL,GAAG;AAAA,EACL,CAAC;AACH;AAQA,SAAS,YAAY,KAAc,KAAe,OAAqB,SAAwB;AAC7F,QAAM,OAAQ,IACZ,QAAQ,mBACV;AACA,QAAM,aACJ,MAAM,cAAc,SAAY,QAAQ,WAAW,KAAK,UAAU,QAAQ,IAAI,KAAK,IAAI;AACzF,QAAM,eAAe,KAAK,IAAI,KAAM,UAAU;AAC9C,MAAI,CAAC,IAAI,UAAU,aAAa,GAAG;AACjC,QAAI,UAAU,eAAe,OAAO,KAAK,KAAK,eAAe,GAAI,CAAC,CAAC;AAAA,EACrE;AACA,MAAI,UAAU,iBAAiB,UAAU;AACzC,MAAI,UAAU,0BAA0B,SAAS;AACjD,MAAI,OAAO,QAAQ,UAAU,EAAE,KAAK;AAAA,IAClC,IAAI;AAAA,IACJ,GAAG,EAAE,MAAM,gBAAgB,SAAS,uBAAuB,MAAM,EAAE,aAAa,EAAE;AAAA,EACpF,CAAC;AACH;AAWO,SAAS,kBAAkB,YAA4B,CAAC,GAA4B;AACzF,SAAO,sBAAsB;AAAA,IAC3B,UAAU,KAAK;AAAA,IACf,KAAK;AAAA,IACL,SAAS;AAAA,IACT,GAAG;AAAA,EACL,CAAC;AACH;","names":[]}
|