@fitzzero/quickdraw-core 5.0.0-rc.7 → 5.0.0

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.
Files changed (85) hide show
  1. package/README.md +18 -19
  2. package/dist/{admin-CsXR7Zwy.d.ts → admin-BiU4LRZS.d.ts} +1 -1
  3. package/dist/{adminSchemas-Dufu8r7a.d.ts → adminSchemas-k5a1Ov7b.d.ts} +1 -1
  4. package/dist/{caller-N1zmIB8c.d.ts → caller-DHzK3oiI.d.ts} +1 -1
  5. package/dist/{chunk-6FFNAT7S.js → chunk-2XJFNVHW.js} +2 -2
  6. package/dist/chunk-2XJFNVHW.js.map +1 -0
  7. package/dist/{chunk-V3KNCTXJ.js → chunk-4YO5H5ON.js} +1 -1
  8. package/dist/chunk-4YO5H5ON.js.map +1 -0
  9. package/dist/{chunk-FMOLH6PL.js → chunk-5IC5VZ7T.js} +3 -3
  10. package/dist/{chunk-3I7R3DZW.js → chunk-5YRQ26LF.js} +1 -1
  11. package/dist/chunk-5YRQ26LF.js.map +1 -0
  12. package/dist/{chunk-DEXRBC5F.js → chunk-7QIY2DDX.js} +3 -3
  13. package/dist/chunk-7QIY2DDX.js.map +1 -0
  14. package/dist/{chunk-6G663RIR.js → chunk-B2P7AZ25.js} +3 -3
  15. package/dist/chunk-B2P7AZ25.js.map +1 -0
  16. package/dist/{chunk-NKVWV3FL.js → chunk-B2UQ27GH.js} +1 -1
  17. package/dist/chunk-B2UQ27GH.js.map +1 -0
  18. package/dist/{chunk-XPTZFIWZ.js → chunk-DD4SKCNO.js} +2 -2
  19. package/dist/chunk-DD4SKCNO.js.map +1 -0
  20. package/dist/{chunk-RLEHORXX.js → chunk-DNCAI3KY.js} +3 -3
  21. package/dist/{chunk-3OYVPO4L.js → chunk-IRGAGRVG.js} +6 -6
  22. package/dist/chunk-IRGAGRVG.js.map +1 -0
  23. package/dist/{chunk-X7T25LME.js → chunk-LLLYILEP.js} +9 -9
  24. package/dist/chunk-LLLYILEP.js.map +1 -0
  25. package/dist/{chunk-FMEHXFPL.js → chunk-QEKVYG5F.js} +2 -2
  26. package/dist/chunk-QEKVYG5F.js.map +1 -0
  27. package/dist/{chunk-X2YCUIEK.js → chunk-REX5YPHX.js} +2 -2
  28. package/dist/chunk-REX5YPHX.js.map +1 -0
  29. package/dist/{chunk-KR7K4QEY.js → chunk-X5CWPX7H.js} +1 -1
  30. package/dist/chunk-X5CWPX7H.js.map +1 -0
  31. package/dist/{chunk-7N6GOASM.js → chunk-XFDOGTMC.js} +5 -5
  32. package/dist/chunk-XFDOGTMC.js.map +1 -0
  33. package/dist/{chunk-BXN7CACY.js → chunk-XUSN5WKU.js} +7 -7
  34. package/dist/chunk-XUSN5WKU.js.map +1 -0
  35. package/dist/{chunk-G47OHQYB.js → chunk-YSWH776Y.js} +1 -1
  36. package/dist/chunk-YSWH776Y.js.map +1 -0
  37. package/dist/cli/quickdraw-docs.js +1 -1
  38. package/dist/client/index.d.ts +3 -3
  39. package/dist/client/index.js +9 -9
  40. package/dist/client/index.js.map +1 -1
  41. package/dist/{clientTypes-rfpWR8yz.d.ts → clientTypes-B3o_99Xq.d.ts} +1 -1
  42. package/dist/{createServer-BxcXQlk8.d.ts → createServer-DUacdfKl.d.ts} +2 -2
  43. package/dist/{createTestApp-CY-RpwCu.d.ts → createTestApp-DFLXoTKm.d.ts} +3 -3
  44. package/dist/{http-DywMt0Yf.d.ts → http--uoooIH5.d.ts} +1 -1
  45. package/dist/index.d.ts +4 -4
  46. package/dist/index.js +7 -7
  47. package/dist/index.js.map +1 -1
  48. package/dist/prisma/index.d.ts +1 -1
  49. package/dist/prisma/index.js +4 -4
  50. package/dist/prisma/index.js.map +1 -1
  51. package/dist/server/auth/index.js +3 -3
  52. package/dist/server/index.d.ts +10 -10
  53. package/dist/server/index.js +12 -12
  54. package/dist/server/index.js.map +1 -1
  55. package/dist/server/mcp/index.d.ts +2 -2
  56. package/dist/server/mcp/index.js +5 -5
  57. package/dist/server/mcp/index.js.map +1 -1
  58. package/dist/{sharing-BSTPqvgD.d.ts → sharing-n4ss-ONM.d.ts} +2 -2
  59. package/dist/testing/client.d.ts +7 -7
  60. package/dist/testing/client.js +9 -9
  61. package/dist/testing/client.js.map +1 -1
  62. package/dist/testing/index.d.ts +6 -6
  63. package/dist/testing/index.js +9 -9
  64. package/dist/testing/index.js.map +1 -1
  65. package/dist/testing/mock.d.ts +3 -3
  66. package/dist/testing/mock.js +8 -8
  67. package/dist/utils/index.js +3 -3
  68. package/package.json +1 -1
  69. package/dist/chunk-3I7R3DZW.js.map +0 -1
  70. package/dist/chunk-3OYVPO4L.js.map +0 -1
  71. package/dist/chunk-6FFNAT7S.js.map +0 -1
  72. package/dist/chunk-6G663RIR.js.map +0 -1
  73. package/dist/chunk-7N6GOASM.js.map +0 -1
  74. package/dist/chunk-BXN7CACY.js.map +0 -1
  75. package/dist/chunk-DEXRBC5F.js.map +0 -1
  76. package/dist/chunk-FMEHXFPL.js.map +0 -1
  77. package/dist/chunk-G47OHQYB.js.map +0 -1
  78. package/dist/chunk-KR7K4QEY.js.map +0 -1
  79. package/dist/chunk-NKVWV3FL.js.map +0 -1
  80. package/dist/chunk-V3KNCTXJ.js.map +0 -1
  81. package/dist/chunk-X2YCUIEK.js.map +0 -1
  82. package/dist/chunk-X7T25LME.js.map +0 -1
  83. package/dist/chunk-XPTZFIWZ.js.map +0 -1
  84. /package/dist/{chunk-FMOLH6PL.js.map → chunk-5IC5VZ7T.js.map} +0 -0
  85. /package/dist/{chunk-RLEHORXX.js.map → chunk-DNCAI3KY.js.map} +0 -0
package/README.md CHANGED
@@ -25,20 +25,19 @@ single hand-written event.
25
25
  - **Testing**: a real test server, access matrices, performance budgets that
26
26
  count statements and bytes, strict development warnings.
27
27
 
28
- Design record: [`docs/rfcs/0003-v5.md`](https://github.com/fitzzero/quickdraw/blob/dev/docs/rfcs/0003-v5.md).
28
+ Design record: [`docs/rfcs/0003-v5.md`](https://github.com/fitzzero/quickdraw/blob/main/docs/rfcs/0003-v5.md).
29
29
 
30
30
  ## Install
31
31
 
32
32
  ```bash
33
- bun add @fitzzero/quickdraw-core@next zod
33
+ bun add @fitzzero/quickdraw-core zod
34
34
  bun add express socket.io @prisma/client # the server
35
35
  bun add socket.io-client @tanstack/react-query react # the web app
36
- bun add -d @fitzzero/quickdraw-lint@next @fitzzero/quickdraw-skills@next oxlint
36
+ bun add -d @fitzzero/quickdraw-lint @fitzzero/quickdraw-skills oxlint
37
37
  ```
38
38
 
39
- Until 5.0.0 is released, 5.0 is published under the `next` dist-tag, which
40
- these commands name; without it they install 4.x. Node 24 or later. Every
41
- peer dependency is optional: install the ones the entries you import need.
39
+ Node 24 or later. Every peer dependency is optional: install the ones the
40
+ entries you import need.
42
41
 
43
42
  | Entry | Needs |
44
43
  | --------------------------------------- | ----------------------------------------------------------------------- |
@@ -59,7 +58,7 @@ peer dependency is optional: install the ones the entries you import need.
59
58
  A board of tasks in the quickdraw template's layout: contracts in
60
59
  `packages/shared`, the server in `apps/api`, the web app in `apps/web`. The
61
60
  examples in this README compile: they are copies of
62
- [`packages/core/test/readme/`](https://github.com/fitzzero/quickdraw/tree/dev/packages/core/test/readme),
61
+ [`packages/core/test/readme/`](https://github.com/fitzzero/quickdraw/tree/main/packages/core/test/readme),
63
62
  which the package's typecheck builds. The pieces the quick start imports
64
63
  without showing (the schemas, the auth helpers, the Prisma models) are under
65
64
  [The example app](#the-example-app).
@@ -319,7 +318,7 @@ and `countOnBoard` is fetched again because it watches the board.
319
318
 
320
319
  The quick start is part of a small app in the template's layout, whose
321
320
  every file compiles with the package:
322
- [`packages/core/test/readme/`](https://github.com/fitzzero/quickdraw/tree/dev/packages/core/test/readme).
321
+ [`packages/core/test/readme/`](https://github.com/fitzzero/quickdraw/tree/main/packages/core/test/readme).
323
322
  The label and project services the server registers are there, with the
324
323
  other sections' examples. These are the pieces the quick start imports
325
324
  without showing, which an app writes itself.
@@ -957,7 +956,7 @@ export const taskService = qd.defineService(task, {
957
956
  Valkey's clock in microseconds, so revisions from all nodes are one order;
958
957
  its key needs persistence or replication. A node whose Valkey connection
959
958
  comes back has its clients reconnect to catch up.
960
- [docs/deploying.md](https://github.com/fitzzero/quickdraw/blob/dev/docs/deploying.md) has the wiring, what holds across
959
+ [docs/deploying.md](https://github.com/fitzzero/quickdraw/blob/main/docs/deploying.md) has the wiring, what holds across
961
960
  nodes, what it costs, and what happens when a node or Valkey stops
962
961
  answering.
963
962
 
@@ -1483,9 +1482,9 @@ such code, and `createInvalidationCoordinator(queryClient)` invalidates as
1483
1482
  the hooks do.
1484
1483
 
1485
1484
  A client in another language (a Godot game, a native app) speaks the wire
1486
- itself: [`docs/protocol-v5.md`](https://github.com/fitzzero/quickdraw/blob/dev/docs/protocol-v5.md) is its specification,
1487
- generated from the protocol's source, and [`examples/godot`](https://github.com/fitzzero/quickdraw/tree/dev/examples/godot)
1488
- holds a GDScript client written from it. [`docs/clients.md`](https://github.com/fitzzero/quickdraw/blob/dev/docs/clients.md)
1485
+ itself: [`docs/protocol-v5.md`](https://github.com/fitzzero/quickdraw/blob/main/docs/protocol-v5.md) is its specification,
1486
+ generated from the protocol's source, and [`examples/godot`](https://github.com/fitzzero/quickdraw/tree/main/examples/godot)
1487
+ holds a GDScript client written from it. [`docs/clients.md`](https://github.com/fitzzero/quickdraw/blob/main/docs/clients.md)
1489
1488
  compares the three ways in.
1490
1489
 
1491
1490
  ## Kits
@@ -3103,7 +3102,7 @@ nothing. Run `--check` in CI next to the lint step.
3103
3102
 
3104
3103
  ## Lint rules and agent guidance
3105
3104
 
3106
- [`@fitzzero/quickdraw-lint`](https://github.com/fitzzero/quickdraw/tree/dev/packages/lint) is the oxlint plugin and base
3105
+ [`@fitzzero/quickdraw-lint`](https://github.com/fitzzero/quickdraw/tree/main/packages/lint) is the oxlint plugin and base
3107
3106
  config every 5.0 app extends: it reports untracked and foreign writes, nested
3108
3107
  and raw SQL writes, hand-sent frames, inline auth guards, unbounded reads,
3109
3108
  database calls and emits in loops, layering breaks, bypasses of the typed
@@ -3118,7 +3117,7 @@ takes an `id`, unless it says `rowless: true`); then lint; then a
3118
3117
  development warning as it happens (`repeated-call`, `repeated-mutation` and
3119
3118
  `repeated-invalidation` name a client loop before the rate limit does).
3120
3119
 
3121
- [`@fitzzero/quickdraw-skills`](https://github.com/fitzzero/quickdraw/tree/dev/packages/skills) ships agent rules and skills
3120
+ [`@fitzzero/quickdraw-skills`](https://github.com/fitzzero/quickdraw/tree/main/packages/skills) ships agent rules and skills
3122
3121
  for quickdraw apps and links them into `.claude/` with
3123
3122
  `quickdraw-skills link`, so every app's agents read the same, current
3124
3123
  guidance:
@@ -3134,17 +3133,17 @@ guidance:
3134
3133
 
3135
3134
  ## Migrating from 4.x
3136
3135
 
3137
- [`@fitzzero/quickdraw-codemod`](https://github.com/fitzzero/quickdraw/tree/dev/packages/codemod) moves a 4.x app to 5.0:
3136
+ [`@fitzzero/quickdraw-codemod`](https://github.com/fitzzero/quickdraw/tree/main/packages/codemod) moves a 4.x app to 5.0:
3138
3137
  contracts from the method maps, `defineService` from the service classes,
3139
3138
  the typed client for the hooks, and a report of everything left to decide.
3140
- [`MIGRATION.md`](https://github.com/fitzzero/quickdraw/blob/dev/MIGRATION.md) explains each step, the access mapping and
3141
- the defaults that changed; [`UPGRADE-PROMPT.md`](https://github.com/fitzzero/quickdraw/blob/dev/UPGRADE-PROMPT.md) is the
3139
+ [`MIGRATION.md`](https://github.com/fitzzero/quickdraw/blob/main/MIGRATION.md) explains each step, the access mapping and
3140
+ the defaults that changed; [`UPGRADE-PROMPT.md`](https://github.com/fitzzero/quickdraw/blob/main/UPGRADE-PROMPT.md) is the
3142
3141
  procedure for an agent. Both ship with the codemod, at
3143
3142
  `node_modules/@fitzzero/quickdraw-codemod/MIGRATION.md` and
3144
3143
  `node_modules/@fitzzero/quickdraw-codemod/UPGRADE-PROMPT.md`.
3145
3144
 
3146
3145
  ```bash
3147
- bunx @fitzzero/quickdraw-codemod@next v5 .
3146
+ bunx @fitzzero/quickdraw-codemod v5 .
3148
3147
  ```
3149
3148
 
3150
3149
  ## Package exports
@@ -3172,7 +3171,7 @@ The package also ships the `quickdraw-docs` command.
3172
3171
 
3173
3172
  A bun workspace with turbo: `packages/core` (this package), `packages/lint`,
3174
3173
  `packages/skills` and `packages/codemod`. See
3175
- [CONTRIBUTING.md](https://github.com/fitzzero/quickdraw/blob/dev/CONTRIBUTING.md).
3174
+ [CONTRIBUTING.md](https://github.com/fitzzero/quickdraw/blob/main/CONTRIBUTING.md).
3176
3175
 
3177
3176
  ```bash
3178
3177
  bun install
@@ -1,5 +1,5 @@
1
1
  import { e as StandardSchemaWithJSON, d as StandardSchemaV1, I as InferInput, c as InferOutput, X as RowSchema, Q as QueryDef, P as ProjectionList, p as MutationDef, J as AnyContract, ap as MethodName } from './infer-Dw21kmLw.js';
2
- import { d as ListSort, c as ListQuery, b as ListPage, u as AdminListInput, v as AdminListQuery, y as AdminPage, r as AdminCreateInput, s as AdminCreateQuery, B as AdminUpdateInput, C as AdminUpdateQuery, w as AdminMetaInput, n as AdminServiceMeta, z as AdminSubscribers } from './adminSchemas-Dufu8r7a.js';
2
+ import { d as ListSort, c as ListQuery, b as ListPage, u as AdminListInput, v as AdminListQuery, y as AdminPage, r as AdminCreateInput, s as AdminCreateQuery, B as AdminUpdateInput, C as AdminUpdateQuery, w as AdminMetaInput, n as AdminServiceMeta, z as AdminSubscribers } from './adminSchemas-k5a1Ov7b.js';
3
3
 
4
4
  /** A schema a kit generates: validation, and its JSON Schema. */
5
5
  type KitSchema<Input, Output = Input> = StandardSchemaWithJSON<Input, Output>;
@@ -136,7 +136,7 @@ interface AdminServiceMeta {
136
136
  /**
137
137
  * Fields no admin call writes, whatever the service configures: the row's key
138
138
  * and its timestamps, which the database sets (4.1's non-editable fields,
139
- * `legacy-src/server/utils/zodToAdminFields.ts:7`).
139
+ * 4.1 `src/server/utils/zodToAdminFields.ts:7`).
140
140
  */
141
141
  declare const ADMIN_NEVER_WRITABLE: readonly string[];
142
142
 
@@ -659,7 +659,7 @@ interface ServerRooms {
659
659
  /**
660
660
  * `ctx.rooms` (RFC 0003 sections 3, 12.5 and 15): app-defined rooms the
661
661
  * calling socket joins and leaves, and typed room events. It replaces 4.1's
662
- * `emitToRoom` and `emitToUserRoom` (`legacy-src/server/BaseService.ts:378-441`).
662
+ * `emitToRoom` and `emitToUserRoom` (4.1 `src/server/BaseService.ts:378-441`).
663
663
  * Everything that needs no calling socket is also on `qd.rooms`
664
664
  * ({@link ServerRooms}).
665
665
  */
@@ -7,7 +7,7 @@ import {
7
7
  INTERNAL_MESSAGE,
8
8
  QuickdrawError,
9
9
  isErrorCode
10
- } from "./chunk-V3KNCTXJ.js";
10
+ } from "./chunk-4YO5H5ON.js";
11
11
 
12
12
  // src/server/caller.ts
13
13
  var CALLER_GRANTS = /* @__PURE__ */ new WeakMap();
@@ -699,4 +699,4 @@ export {
699
699
  createContext,
700
700
  withSignal
701
701
  };
702
- //# sourceMappingURL=chunk-6FFNAT7S.js.map
702
+ //# sourceMappingURL=chunk-2XJFNVHW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/caller.ts","../src/server/pipeline/errors.ts","../src/server/pipeline/schemaOutput.ts","../src/server/pipeline/validation.ts","../src/server/context.ts"],"sourcesContent":["// The in-process caller (RFC 0003 section 10): `caller.taskService.rename(input)`\n// runs the same pipeline as a socket call, with transport `\"internal\"`. Its\n// types come from the contracts: a method takes what a client would pass\n// (`InputOf`) and resolves with what a client would receive (`OutputOf`).\n// A failed call rejects with its `QuickdrawError`; an `INTERNAL` one keeps\n// the original error as `cause`.\n//\n// A caller through a server's dispatcher (`qd.caller`, `server.dispatcher.caller`)\n// gives a principal that carries no `serviceAccess` the grants the server's\n// `auth.loadServiceAccess` loads, as a socket's handshake and an HTTP call\n// do (finding F5.1 of the quickdraw-chat migration: an app's REST route ran\n// its in-process call with no grants at all): once per caller, at its first\n// call, and again after the server applied new grants to a user\n// (`access.refresh`, a written grant, another node's broadcast), as a\n// socket's are refreshed. A principal that carries grants, even `{}`, keeps\n// exactly those.\n\nimport type { AnyContract } from \"../contract/defineContract\";\nimport type { ContractMap, InputOf, MethodName, OutputOf } from \"../contract/infer\";\nimport { INTERNAL_MESSAGE, QuickdrawError } from \"../protocol/errors\";\nimport type { Dispatch } from \"./pipeline/pipeline\";\nimport type { DispatchRequest } from \"./pipeline/request\";\nimport type { ServerAuth } from \"./transports/auth\";\nimport type { Principal, QuickdrawTypes } from \"./types\";\n\n/** Options of one in-process call. */\nexport interface CallOptions {\n /** Cancels the call (queries only), like a client's `qd:cancel`. */\n readonly signal?: AbortSignal;\n}\n\n/** One method of the in-process caller. The input may be left out when the method accepts `undefined`. */\nexport type MethodCaller<C extends AnyContract, M extends MethodName<C>> = (\n ...args: undefined extends InputOf<C, M>\n ? [input?: InputOf<C, M>, options?: CallOptions]\n : [input: InputOf<C, M>, options?: CallOptions]\n) => Promise<OutputOf<C, M>>;\n\n/** The in-process caller of one service: one function per method. */\nexport type ServiceCaller<C extends AnyContract> = {\n readonly [M in MethodName<C>]: MethodCaller<C, M>;\n};\n\n/** The in-process caller of a set of contracts, by service name: `caller.taskService.rename(input)`. */\nexport type Caller<C extends AnyContract> = {\n readonly [Name in C[\"name\"]]: ServiceCaller<Extract<C, { readonly name: Name }>>;\n};\n\n/**\n * The type of `qd.caller(principal)`: typed from the app's `contracts` when\n * `QuickdrawTypes` declares them, and untyped (any service, method and\n * input) otherwise.\n */\nexport type CallerFor<T extends QuickdrawTypes> = T extends {\n readonly contracts: infer Contracts extends ContractMap;\n}\n ? Caller<Contracts[keyof Contracts]>\n : Caller<AnyContract>;\n\n/** Where the in-process callers of a server's dispatcher get the grants of a principal that carries none. */\nexport interface CallerGrants {\n /** The server's `auth.loadServiceAccess`. */\n readonly load: NonNullable<ServerAuth[\"loadServiceAccess\"]>;\n /**\n * Rises each time the server applies new grants to a user: a caller that\n * loaded its principal's grants before loads them again at its next call.\n */\n readonly version: () => number;\n}\n\nconst CALLER_GRANTS = new WeakMap<object, CallerGrants>();\n\n/**\n * Makes the in-process callers of `dispatcher` (its `caller`, and `qd.caller`\n * while it is the current one) load grants through `grants`: `createServer`\n * registers its `auth.loadServiceAccess`.\n */\nexport function setCallerGrants(dispatcher: object, grants: CallerGrants): void {\n CALLER_GRANTS.set(dispatcher, grants);\n}\n\n/** Where the callers of `dispatcher` load grants from, or `undefined` when they load none. */\nexport function callerGrantsOf(dispatcher: object | undefined): CallerGrants | undefined {\n return dispatcher === undefined ? undefined : CALLER_GRANTS.get(dispatcher);\n}\n\n/** How the calls of a {@link createCaller} run. */\nexport interface CallerSettings {\n /** Cancels every call too: `ctx.services` passes the calling method's `ctx.signal`. */\n readonly signal?: AbortSignal;\n /** Where to load a principal's grants from, asked at each call; `undefined` loads none. */\n readonly grants?: () => CallerGrants | undefined;\n}\n\ntype MethodFunction = (input?: unknown, options?: CallOptions) => Promise<unknown>;\n\nasync function invoke(resolve: () => Dispatch, request: DispatchRequest): Promise<unknown> {\n const result = await resolve()(request);\n if (!result.ok) {\n throw result.error;\n }\n return result.notModified === true ? undefined : result.data;\n}\n\n/**\n * A read-only object whose members are made on first access and kept. It is\n * never mistaken for a promise: `then` reads as `undefined`.\n */\nexport function lazyMembers<Member>(make: (name: string) => Member): object {\n const made = new Map<string, Member>();\n return new Proxy(Object.freeze({}), {\n get(_target, name) {\n if (typeof name !== \"string\" || name === \"then\") {\n return undefined;\n }\n let member = made.get(name);\n if (member === undefined) {\n member = make(name);\n made.set(name, member);\n }\n return member;\n },\n });\n}\n\n/** `signal`, and also `outer` when there is one: aborted when either is. */\nfunction bothSignals(outer: AbortSignal | undefined, signal: AbortSignal | undefined) {\n if (outer === undefined || signal === undefined) {\n return outer ?? signal;\n }\n return AbortSignal.any([outer, signal]);\n}\n\n/** True when `principal` carries grants of its own (`{}` included): they are kept as they are. */\nfunction carriesGrants(principal: Principal): boolean {\n return principal.serviceAccess !== undefined && principal.serviceAccess !== null;\n}\n\n/** `principal` with the grants `grants` loads (`{}` for none). A failed load is `INTERNAL`, keeping the error as `cause`. */\nasync function withLoadedGrants(principal: Principal, grants: CallerGrants): Promise<Principal> {\n let serviceAccess: Awaited<ReturnType<CallerGrants[\"load\"]>>;\n try {\n serviceAccess = await grants.load(principal.userId);\n } catch (error) {\n const failure = new QuickdrawError(\"INTERNAL\", INTERNAL_MESSAGE);\n failure.cause = error;\n throw failure;\n }\n return { ...principal, serviceAccess: serviceAccess ?? {} };\n}\n\n/** What each call of a caller runs as: the principal, or a promise of it while its grants load. */\ntype PrincipalOfCall = () => Principal | null | Promise<Principal>;\n\n/**\n * The principal each call of a caller runs as: `principal` itself when it is\n * `null`, carries grants, or `grants` gives no loader; else `principal` with\n * the grants loaded at the first call, kept until the server applied new\n * grants to a user (its version rose) or the loader changed. A load that\n * failed is not kept: the next call loads again.\n */\nfunction principalOfCalls(\n principal: Principal | null,\n grants: CallerSettings[\"grants\"],\n): PrincipalOfCall {\n if (principal === null || carriesGrants(principal) || grants === undefined) {\n return () => principal;\n }\n interface Held {\n readonly from: CallerGrants;\n readonly version: number;\n readonly loading: Promise<Principal>;\n loaded?: Principal;\n }\n let held: Held | undefined;\n return () => {\n const from = grants();\n if (from === undefined) {\n return principal;\n }\n const version = from.version();\n if (held?.from === from && held.version === version) {\n return held.loaded ?? held.loading;\n }\n const entry: Held = { from, version, loading: withLoadedGrants(principal, from) };\n held = entry;\n entry.loading.then(\n (loaded) => {\n entry.loaded = loaded;\n },\n () => {\n if (held === entry) {\n held = undefined;\n }\n },\n );\n return entry.loading;\n };\n}\n\n/**\n * Creates an in-process caller acting as `principal` (`null` for an\n * anonymous caller). `resolve` returns the dispatch function to call through;\n * it is asked on every call, so a caller made before its dispatcher exists\n * works once one does. Every call is also cancelled with `settings.signal`,\n * when given (`ctx.services` passes the calling method's `ctx.signal`). With\n * `settings.grants`, a principal that carries no grants calls with the ones\n * it loads (see the top of this file).\n */\nexport function createCaller(\n resolve: () => Dispatch,\n principal: Principal | null,\n settings: CallerSettings = {},\n): object {\n const principalOfCall = principalOfCalls(principal, settings.grants);\n return lazyMembers((service) =>\n lazyMembers<MethodFunction>((method) => async (input, options) => {\n const runAs = principalOfCall();\n return await invoke(resolve, {\n service,\n method,\n input,\n // Awaited only while grants load: a known principal is dispatched at once, as before.\n principal: runAs instanceof Promise ? await runAs : runAs,\n transport: \"internal\",\n signal: bothSignals(settings.signal, options?.signal),\n });\n }),\n );\n}\n","// How the pipeline turns whatever a stage or handler threw into the error the\n// caller receives (RFC 0003 section 3). A `QuickdrawError` with one of the\n// error codes passes through. Prisma's two known request errors that callers\n// can act on become `CONFLICT` and `NOT_FOUND`. Everything else becomes\n// `INTERNAL` with the generic message, keeping the original as `cause` for\n// the log and for in-process callers; `toWire` never sends it. That includes\n// a `QuickdrawError` whose code is not one of the error codes, which a cast or\n// a 4.x port (`new QuickdrawError(404, ...)`) can build: no transport has a\n// reply or an HTTP status for it.\n\nimport { INTERNAL_MESSAGE, isErrorCode, QuickdrawError } from \"../../protocol/errors\";\n\n/** The error a cancelled call settles with. */\nexport function cancelledError(): QuickdrawError {\n return new QuickdrawError(\"CANCELLED\", \"The call was cancelled\");\n}\n\n/** The error a call settles with when its handler runs past the time limit. */\nexport function timeoutError(timeoutMs: number): QuickdrawError {\n return new QuickdrawError(\"TIMEOUT\", `The call ran past its time limit of ${timeoutMs} ms`);\n}\n\n/** Throws `CANCELLED` when `signal` has aborted. */\nexport function throwIfCancelled(signal: AbortSignal | undefined): void {\n if (signal?.aborted === true) {\n throw cancelledError();\n }\n}\n\n/**\n * The error a call settles with once its signal aborted: the `TIMEOUT` error\n * its time limit aborted it with, or else `CANCELLED`.\n */\nexport function abortError(signal: AbortSignal): QuickdrawError {\n const reason: unknown = signal.reason;\n return reason instanceof QuickdrawError && reason.code === \"TIMEOUT\" ? reason : cancelledError();\n}\n\nfunction prismaError(error: unknown): QuickdrawError | undefined {\n if (!(error instanceof Error) || error.name !== \"PrismaClientKnownRequestError\") {\n return undefined;\n }\n const { code } = error as Error & { readonly code?: unknown };\n if (code === \"P2002\") {\n return new QuickdrawError(\"CONFLICT\", \"A unique constraint failed\");\n }\n if (code === \"P2025\") {\n return new QuickdrawError(\"NOT_FOUND\", \"Record not found\");\n }\n return undefined;\n}\n\n/**\n * The `QuickdrawError` a caller receives for `error`. Anything but a\n * `QuickdrawError` with a known code becomes another error that keeps the\n * original as `cause`, so it can be logged in full.\n */\nexport function toQuickdrawError(error: unknown): QuickdrawError {\n if (error instanceof QuickdrawError && isErrorCode(error.code)) {\n return error;\n }\n const mapped = prismaError(error) ?? new QuickdrawError(\"INTERNAL\", INTERNAL_MESSAGE);\n mapped.cause = error;\n return mapped;\n}\n","// Schema outputs (RFC 0003 section 9, step 8): a method whose output is a\n// schema of its own, not `\"entity\"` and not a projection, sends its result\n// reduced to what that schema's JSON Schema declares, on every transport and\n// whatever `outputValidation` is. A handler may return a whole row; only the\n// keys the schema declares leave the server. rc.5 and before sent what the\n// handler returned, so `{ id, name }` answered with `db.user.update(...)`\n// sent `email` too (the final review of the release candidates, item B).\n//\n// The reduction is compiled once per method, when its service is defined,\n// from the schema's Standard JSON Schema (draft-07, a value JSON Schema\n// cannot write read as any value): a call walks the compiled shapes and\n// never reads the schema. What a value keeps, by what the schema says there:\n//\n// | JSON Schema | A value there keeps |\n// |-------------------------------------------|------------------------------------------------------|\n// | an object with `properties` | the keys `properties` declares, each reduced by its |\n// | | own schema; another key only where |\n// | | `patternProperties` matches it or |\n// | | `additionalProperties` allows it (`true`, `{}`, or a |\n// | | schema that reduces its value) |\n// | an object declaring no key (a record, | every key, each value reduced by |\n// | `{ type: \"object\" }`) | `additionalProperties` when it is a schema |\n// | an array | its items, each reduced by `items` (a tuple's by |\n// | | position, the rest by `additionalItems`) |\n// | `anyOf`, `oneOf`, `allOf` | what any of its schemas keeps |\n// | `{}` (any value), `true`, a `$ref` it | everything, as it is |\n// | cannot follow | |\n// | a scalar (`string`, `const`, `enum`, ...) | a scalar as it is; a plain object there keeps no key |\n//\n// Only plain objects and arrays are reduced: a `Date`, a `Decimal` or a\n// class instance goes as it is. Nothing is copied unless a key or an item is\n// dropped, so a handler that returns exactly its schema's keys costs one\n// pass over them. An output without JSON Schema (a Zod 3 schema) cannot be\n// reduced and is sent as returned; in development its reply is checked for\n// keys the contract tiers instead (`emit/tieredOutputs.ts`).\n\nimport { hasJsonSchema, type StandardSchemaV1 } from \"../../contract/standardSchema\";\nimport type { SchemaOutput } from \"../service\";\n\ntype JsonNode = Readonly<Record<string, unknown>>;\n\n/** How the values at one place of an output are reduced. */\ninterface Shape {\n /** Any value: kept as it is. */\n readonly any: boolean;\n /** How a plain object there is reduced; without one, it keeps no key. */\n object: ObjectShape | undefined;\n /** How an array there is reduced; without one, each item is reduced by this shape. */\n array: ArrayShape | undefined;\n}\n\ninterface ObjectShape {\n /** The declared keys' shapes, in an object without a prototype: a lookup per key is a property read. */\n readonly properties: Readonly<Record<string, Shape | undefined>>;\n readonly patterns: readonly { readonly regex: RegExp; readonly shape: Shape }[];\n /** How the value of a key `properties` and `patterns` do not declare is reduced; `undefined` drops the key. */\n readonly additional: Shape | undefined;\n}\n\ninterface ArrayShape {\n readonly prefix: readonly Shape[];\n /** How the items past `prefix` are reduced; `undefined` drops them. */\n readonly rest: Shape | undefined;\n}\n\n/** Any value, kept as it is. */\nconst ANY: Shape = Object.freeze({ any: true, object: undefined, array: undefined });\n\n/** What one JSON Schema node declares on its own, before its `anyOf`, `oneOf`, `allOf` and `$ref`. */\ninterface Node {\n readonly id: number;\n any: boolean;\n object:\n | {\n properties: Map<string, Node>;\n patterns: { regex: RegExp; node: Node }[];\n additional: Node | undefined;\n }\n | undefined;\n array: { prefix: Node[]; rest: Node | undefined } | undefined;\n /** The schemas it is one of, or all of: its branches and the node its `$ref` names. */\n readonly members: Node[];\n}\n\nfunction isRecord(value: unknown): value is JsonNode {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** True for an object literal, or `Object.create(null)`, of any realm: what a reduction may copy. */\nfunction isPlainObject(value: object): value is Readonly<Record<string, unknown>> {\n const prototype = Object.getPrototypeOf(value) as object | null;\n return (\n prototype === Object.prototype ||\n prototype === null ||\n Object.getPrototypeOf(prototype) === null\n );\n}\n\n/** The node a `$ref` names in the document: `#`, or a JSON Pointer into it; `undefined` when it names none. */\nfunction follow(ref: string, root: JsonNode): unknown {\n if (ref === \"#\") {\n return root;\n }\n if (!ref.startsWith(\"#/\")) {\n return undefined;\n }\n let node: unknown = root;\n for (const raw of ref.slice(2).split(\"/\")) {\n let part: string;\n try {\n part = decodeURIComponent(raw).replaceAll(\"~1\", \"/\").replaceAll(\"~0\", \"~\");\n } catch {\n return undefined;\n }\n node = isRecord(node) && Object.hasOwn(node, part) ? node[part] : undefined;\n }\n return node;\n}\n\nconst BRANCHES = [\"anyOf\", \"oneOf\", \"allOf\"] as const;\n\nfunction hasAny(node: JsonNode, keywords: readonly string[]): boolean {\n return keywords.some((keyword) => node[keyword] !== undefined);\n}\n\nfunction typesOf(node: JsonNode): readonly unknown[] | undefined {\n const { type } = node;\n if (typeof type === \"string\") {\n return [type];\n }\n return Array.isArray(type) ? type : undefined;\n}\n\nfunction patternOf(source: string): RegExp | undefined {\n try {\n return new RegExp(source, \"u\");\n } catch {\n try {\n return new RegExp(source);\n } catch {\n return undefined;\n }\n }\n}\n\n/** Every node `nodes` stand for: themselves and, through their members, the schemas they combine. */\nfunction expand(nodes: readonly Node[]): Node[] {\n const seen = new Set<Node>();\n const pending = [...nodes];\n for (let node = pending.pop(); node !== undefined; node = pending.pop()) {\n if (!seen.has(node)) {\n seen.add(node);\n pending.push(...node.members);\n }\n }\n return [...seen];\n}\n\n/**\n * Compiles one JSON Schema document: reads it into nodes (each JSON node\n * once, `$ref` cycles included), then builds the shapes calls walk, one per\n * set of nodes a value may meet, merged once.\n */\nclass Compiler {\n private next = 0;\n private readonly nodes = new Map<unknown, Node>();\n private readonly shapes = new Map<string, Shape>();\n\n constructor(private readonly root: JsonNode) {}\n\n private make(any: boolean): Node {\n this.next += 1;\n return { id: this.next, any, object: undefined, array: undefined, members: [] };\n }\n\n /** The node a JSON Schema value stands for. `true` and absent are any value. */\n read(value: unknown): Node {\n if (value === undefined || value === true) {\n return this.make(true);\n }\n if (!isRecord(value)) {\n // `false` (no value) and anything malformed: a scalar, which keeps no key of an object.\n return this.make(false);\n }\n const known = this.nodes.get(value);\n if (known !== undefined) {\n return known;\n }\n const node = this.make(false);\n this.nodes.set(value, node);\n this.readMembers(node, value);\n this.readParts(node, value);\n return node;\n }\n\n /** The node's `$ref` target and its `anyOf`, `oneOf` and `allOf` branches. */\n private readMembers(node: Node, json: JsonNode): void {\n const { $ref } = json;\n if (typeof $ref === \"string\") {\n const target = follow($ref, this.root);\n node.members.push(target === undefined ? this.make(true) : this.read(target));\n }\n for (const keyword of BRANCHES) {\n const members = json[keyword];\n if (!Array.isArray(members)) {\n continue;\n }\n for (const member of members) {\n const read = this.read(member);\n // A part of an `allOf` that allows any value adds nothing to the others.\n if (!(keyword === \"allOf\" && read.any && members.length > 1)) {\n node.members.push(read);\n }\n }\n }\n }\n\n /** What the node declares itself: an object, an array, a scalar, or any value. */\n private readParts(node: Node, json: JsonNode): void {\n const types = typesOf(json);\n const combined = node.members.length > 0;\n const objectKeywords = hasAny(json, [\n \"properties\",\n \"patternProperties\",\n \"additionalProperties\",\n ]);\n const arrayKeywords = hasAny(json, [\"items\", \"prefixItems\", \"additionalItems\"]);\n if (objectKeywords) {\n node.object = this.readObject(json);\n } else if (!combined && types?.includes(\"object\") === true) {\n // An object that declares no key, as a record does: every key.\n node.object = { properties: new Map(), patterns: [], additional: this.make(true) };\n }\n if (arrayKeywords) {\n node.array = this.readArray(json);\n } else if (!combined && types?.includes(\"array\") === true) {\n node.array = { prefix: [], rest: this.make(true) };\n }\n const scalar = types !== undefined || hasAny(json, [\"const\", \"enum\"]);\n node.any = !combined && !objectKeywords && !arrayKeywords && !scalar;\n }\n\n private readObject(json: JsonNode): NonNullable<Node[\"object\"]> {\n const properties = new Map<string, Node>();\n if (isRecord(json.properties)) {\n for (const [key, schema] of Object.entries(json.properties)) {\n properties.set(key, this.read(schema));\n }\n }\n const patterns: { regex: RegExp; node: Node }[] = [];\n let open = false;\n if (isRecord(json.patternProperties)) {\n for (const [source, schema] of Object.entries(json.patternProperties)) {\n const regex = patternOf(source);\n if (regex === undefined) {\n open = true;\n } else {\n patterns.push({ regex, node: this.read(schema) });\n }\n }\n }\n const { additionalProperties } = json;\n let additional: Node | undefined;\n if (open) {\n additional = this.make(true);\n } else if (additionalProperties === undefined) {\n // Properties declared and nothing said of the others: the declared keys only.\n additional =\n json.properties === undefined && json.patternProperties === undefined\n ? this.make(true)\n : undefined;\n } else {\n additional = additionalProperties === false ? undefined : this.read(additionalProperties);\n }\n return { properties, patterns, additional };\n }\n\n private readArray(json: JsonNode): NonNullable<Node[\"array\"]> {\n const { items, prefixItems, additionalItems } = json;\n if (Array.isArray(items)) {\n // draft-07's tuple: `items` by position, `additionalItems` past them.\n return {\n prefix: items.map((item: unknown) => this.read(item)),\n rest: additionalItems === false ? undefined : this.read(additionalItems),\n };\n }\n const prefix = Array.isArray(prefixItems)\n ? prefixItems.map((item: unknown) => this.read(item))\n : [];\n return { prefix, rest: items === false ? undefined : this.read(items) };\n }\n\n /** The shape of a value any of `nodes` describes. */\n shapeOf(nodes: readonly Node[]): Shape {\n const all = expand(nodes);\n if (all.some((node) => node.any)) {\n return ANY;\n }\n const key = all\n .map((node) => node.id)\n .sort((a, b) => a - b)\n .join(\",\");\n const known = this.shapes.get(key);\n if (known !== undefined) {\n return known;\n }\n // Registered before its parts are built, so a recursive schema meets itself.\n const shape: Shape = { any: false, object: undefined, array: undefined };\n this.shapes.set(key, shape);\n const objects = all.flatMap((node) => (node.object === undefined ? [] : [node.object]));\n const arrays = all.flatMap((node) => (node.array === undefined ? [] : [node.array]));\n shape.object = objects.length === 0 ? undefined : this.objectShapeOf(objects);\n shape.array = arrays.length === 0 ? undefined : this.arrayShapeOf(arrays);\n return shape;\n }\n\n private objectShapeOf(objects: readonly NonNullable<Node[\"object\"]>[]): ObjectShape {\n const keys = new Set(objects.flatMap((object) => [...object.properties.keys()]));\n const properties = Object.create(null) as Record<string, Shape>;\n for (const key of keys) {\n const nodes = objects.flatMap((object) => {\n const declared =\n object.properties.get(key) ??\n object.patterns.find(({ regex }) => regex.test(key))?.node ??\n object.additional;\n return declared === undefined ? [] : [declared];\n });\n properties[key] = this.shapeOf(nodes);\n }\n const patterns = objects.flatMap((object) =>\n object.patterns.map(({ regex, node }) => ({ regex, shape: this.shapeOf([node]) })),\n );\n const additional = objects.flatMap((object) =>\n object.additional === undefined ? [] : [object.additional],\n );\n return {\n properties,\n patterns,\n additional: additional.length === 0 ? undefined : this.shapeOf(additional),\n };\n }\n\n private arrayShapeOf(arrays: readonly NonNullable<Node[\"array\"]>[]): ArrayShape {\n const length = Math.max(...arrays.map((array) => array.prefix.length));\n const at = (index: number): Node[] =>\n arrays.flatMap((array) => {\n const node = index < array.prefix.length ? array.prefix[index] : array.rest;\n return node === undefined ? [] : [node];\n });\n const prefix = Array.from({ length }, (_, index) => this.shapeOf(at(index)));\n const rest = arrays.flatMap((array) => (array.rest === undefined ? [] : [array.rest]));\n return { prefix, rest: rest.length === 0 ? undefined : this.shapeOf(rest) };\n }\n}\n\n/** Marks a key or an item a reduction drops. */\nconst DROPPED: unique symbol = Symbol(\"dropped\");\n\n/** Sets `key` on a copy, `__proto__` too, as an own key. */\nfunction assign(copy: Record<string, unknown>, key: string, value: unknown): void {\n if (key === \"__proto__\") {\n Object.defineProperty(copy, key, {\n value,\n enumerable: true,\n writable: true,\n configurable: true,\n });\n } else {\n copy[key] = value;\n }\n}\n\nfunction shapeOfKey(object: ObjectShape, key: string): Shape | undefined {\n const declared = object.properties[key];\n if (declared !== undefined) {\n return declared;\n }\n for (const { regex, shape } of object.patterns) {\n if (regex.test(key)) {\n return shape;\n }\n }\n return object.additional;\n}\n\n/** `item` as `shape` keeps it, or `DROPPED`; a scalar is kept without a call. */\nfunction keep(shape: Shape | undefined, item: unknown): unknown {\n if (shape === undefined) {\n return DROPPED;\n }\n return shape.any || typeof item !== \"object\" || item === null ? item : reduce(shape, item);\n}\n\nfunction reduceObject(\n object: ObjectShape | undefined,\n value: Readonly<Record<string, unknown>>,\n): Readonly<Record<string, unknown>> {\n const keys = Object.keys(value);\n let copy: Record<string, unknown> | undefined;\n for (let index = 0; index < keys.length; index += 1) {\n const key = keys[index] as string;\n const item = value[key];\n const kept = keep(object === undefined ? undefined : shapeOfKey(object, key), item);\n if (copy === undefined) {\n if (kept === item) {\n continue;\n }\n copy = {};\n for (let earlier = 0; earlier < index; earlier += 1) {\n const name = keys[earlier] as string;\n assign(copy, name, value[name]);\n }\n }\n if (kept !== DROPPED) {\n assign(copy, key, kept);\n }\n }\n return copy ?? value;\n}\n\nfunction reduceArray(shape: Shape, value: readonly unknown[]): readonly unknown[] {\n const { array } = shape;\n let copy: unknown[] | undefined;\n for (let index = 0; index < value.length; index += 1) {\n const item: unknown = value[index];\n const kept = keep(\n array === undefined ? shape : index < array.prefix.length ? array.prefix[index] : array.rest,\n item,\n );\n if (copy === undefined) {\n if (kept === item) {\n continue;\n }\n copy = value.slice(0, index);\n }\n if (kept !== DROPPED) {\n copy.push(kept);\n }\n }\n return copy ?? value;\n}\n\n/** An object `value` as `shape` keeps it. */\nfunction reduce(shape: Shape, value: object): unknown {\n if (Array.isArray(value)) {\n return reduceArray(shape, value);\n }\n return isPlainObject(value) ? reduceObject(shape.object, value) : value;\n}\n\n/** Where a shape declares each key it names, at any depth: the shortest path found first. */\nfunction keyPaths(root: Shape): ReadonlyMap<string, string> {\n const paths = new Map<string, string>();\n const seen = new Set<Shape>();\n const queue: { readonly shape: Shape; readonly path: string }[] = [{ shape: root, path: \"\" }];\n for (let index = 0; index < queue.length; index += 1) {\n const { shape, path } = queue[index] as { readonly shape: Shape; readonly path: string };\n if (seen.has(shape)) {\n continue;\n }\n seen.add(shape);\n if (shape.object !== undefined) {\n for (const [key, child] of Object.entries(shape.object.properties)) {\n if (child === undefined) {\n continue;\n }\n const at = path === \"\" ? key : `${path}.${key}`;\n if (!paths.has(key)) {\n paths.set(key, at);\n }\n queue.push({ shape: child, path: at });\n }\n for (const { shape: child } of shape.object.patterns) {\n queue.push({ shape: child, path: `${path}{}` });\n }\n if (shape.object.additional !== undefined) {\n queue.push({ shape: shape.object.additional, path: `${path}{}` });\n }\n }\n if (shape.array !== undefined) {\n for (const child of shape.array.prefix) {\n queue.push({ shape: child, path: `${path}[]` });\n }\n if (shape.array.rest !== undefined) {\n queue.push({ shape: shape.array.rest, path: `${path}[]` });\n }\n }\n }\n return paths;\n}\n\n/** Writes values JSON Schema has no form for as `{}` (any value), keeping the keys beside them (Zod 4). */\nconst UNREPRESENTABLE_AS_ANY = Object.freeze({ unrepresentable: \"any\" });\n\n/**\n * Compiles a method's output schema (see the top of this file), or\n * `undefined` when it has no Standard JSON Schema or cannot write one: such\n * an output is sent as the handler returns it.\n */\nexport function compileSchemaOutput(schema: StandardSchemaV1): SchemaOutput | undefined {\n if (!hasJsonSchema(schema)) {\n return undefined;\n }\n let json: unknown;\n try {\n json = schema[\"~standard\"].jsonSchema.output({\n target: \"draft-07\",\n libraryOptions: UNREPRESENTABLE_AS_ANY,\n });\n } catch {\n return undefined;\n }\n if (!isRecord(json)) {\n return undefined;\n }\n const compiler = new Compiler(json);\n const root = compiler.shapeOf([compiler.read(json)]);\n let paths: ReadonlyMap<string, string> | undefined;\n return Object.freeze({\n pick: (value: unknown) => keep(root, value),\n keyPaths: () => (paths ??= keyPaths(root)),\n });\n}\n","// Input and output validation (RFC 0003 section 9, steps 3 and 8). Input\n// failures reach the caller as `VALIDATION` with `data.issues` in the wire\n// shape `{ path, message }[]`. 4.1 sent Zod's message as a code-400 string\n// (4.1 `src/server/ServiceRegistry.ts:296-305`), and only when the method\n// had a schema at all.\n\nimport type { AnyContract } from \"../../contract/defineContract\";\nimport type { MethodOutput } from \"../../contract/methods\";\nimport {\n isStandardSchema,\n validate,\n type StandardSchemaV1,\n type ValidationIssue,\n} from \"../../contract/standardSchema\";\nimport { QuickdrawError, type WireIssue } from \"../../protocol/errors\";\nimport type { SchemaOutput } from \"../service\";\nimport { compileSchemaOutput } from \"./schemaOutput\";\n\ntype PathSegment = NonNullable<ValidationIssue[\"path\"]>[number];\n\nfunction wireKey(key: PropertyKey): string | number {\n if (typeof key === \"symbol\") {\n return key.description ?? key.toString();\n }\n return key;\n}\n\nfunction wireSegment(segment: PathSegment): string | number {\n return typeof segment === \"object\" ? wireKey(segment.key) : wireKey(segment);\n}\n\n/**\n * Standard Schema issues in the wire shape of RFC 0003 section 3: each path\n * as object keys and array indexes (a `{ key }` segment becomes its key, a\n * symbol its description), and the message unchanged.\n */\nexport function toWireIssues(issues: readonly ValidationIssue[]): WireIssue[] {\n return issues.map((issue) => ({\n path: (issue.path ?? []).map(wireSegment),\n message: issue.message,\n }));\n}\n\n/** Validates a call's input. Resolves with the parsed input, or rejects with `VALIDATION`. */\nexport async function parseInput(\n schema: StandardSchemaV1,\n input: unknown,\n label: string,\n): Promise<unknown> {\n const result = await validate(schema, input);\n if (result.issues !== undefined) {\n throw new QuickdrawError(\"VALIDATION\", `Invalid input for ${label}`, {\n issues: toWireIssues(result.issues),\n });\n }\n return result.value;\n}\n\nfunction derivedSchema(validateValue: StandardSchemaV1.Props[\"validate\"]): StandardSchemaV1 {\n return Object.freeze({\n \"~standard\": Object.freeze({ version: 1, vendor: \"quickdraw\", validate: validateValue }),\n });\n}\n\nfunction nullableOf(inner: StandardSchemaV1): StandardSchemaV1 {\n return derivedSchema((value) =>\n value === null ? { value } : inner[\"~standard\"].validate(value),\n );\n}\n\nfunction listOfSchema(inner: StandardSchemaV1): StandardSchemaV1 {\n return derivedSchema(async (value) => {\n if (!Array.isArray(value)) {\n return { issues: [{ message: \"Expected an array\", path: [] }] };\n }\n const results = await Promise.all(value.map((item: unknown) => validate(inner, item)));\n const issues = results.flatMap((result, index) =>\n (result.issues ?? []).map((issue) => ({\n message: issue.message,\n path: [index, ...(issue.path ?? [])],\n })),\n );\n return issues.length > 0 ? { issues } : { value };\n });\n}\n\nfunction projectionSchema(contract: AnyContract, projection: string): StandardSchemaV1 {\n const found = projection === \"entity\" ? contract.entity : contract.projections[projection];\n if (found === undefined) {\n throw new TypeError(\n `defineService(\"${contract.name}\"): output names unknown projection \"${projection}\"`,\n );\n }\n return found;\n}\n\n/**\n * The schema a method's result is checked against: its `output` schema, or\n * the entity or projection schema it names, wrapped for `nullable(...)` and\n * `listOf(...)` (RFC 0003 section 17).\n */\nexport function outputSchemaOf(contract: AnyContract, output: MethodOutput): StandardSchemaV1 {\n if (isStandardSchema(output)) {\n return output;\n }\n if (typeof output === \"string\") {\n return projectionSchema(contract, output);\n }\n const row = projectionSchema(contract, output.projection);\n return output.kind === \"nullable\" ? nullableOf(row) : listOfSchema(row);\n}\n\n/**\n * A method output that is a schema of its own, compiled to reduce results to\n * what it declares (`schemaOutput.ts`); `undefined` for a projection output\n * or a schema without JSON Schema.\n */\nexport function schemaOutputOf(output: MethodOutput): SchemaOutput | undefined {\n return isStandardSchema(output) ? compileSchemaOutput(output) : undefined;\n}\n\n/** The problems with a handler's result, or `undefined` when it matches the method's output. */\nexport async function outputIssues(\n output: StandardSchemaV1,\n value: unknown,\n): Promise<WireIssue[] | undefined> {\n const result = await validate(output, value);\n return result.issues === undefined ? undefined : toWireIssues(result.issues);\n}\n","// The argument every handler receives, `{ input, ctx, db }` (RFC 0003\n// section 3). `ctx` replaces 4.1's `ServiceMethodContext` (`userId`,\n// `socketId`, `serviceAccess`; 4.1 `src/shared/types.ts:111-115`) and the\n// habit of overriding `defineMethod` to add fields: an app adds its own\n// fields once, through `initQuickdraw({ context })`.\n\nimport type { AnyContract } from \"../contract/defineContract\";\nimport type { Logger } from \"../contract/logger\";\nimport { QuickdrawError } from \"../protocol/errors\";\nimport type { DispatcherAccess, PolicyEngine } from \"./access/api\";\nimport { createCaller, type CallerFor } from \"./caller\";\nimport type { Dispatch } from \"./pipeline/pipeline\";\nimport type { ContextRooms, Presence } from \"./realtime/types\";\nimport type { AnyService } from \"./service\";\nimport type { StorageAdapter } from \"./storage\";\nimport type {\n ContextExtensionOf,\n DbOf,\n McpContext,\n McpContextOf,\n Principal,\n PrincipalOf,\n QuickdrawTypes,\n Transport,\n} from \"./types\";\n\n/** Options of `ctx.touch`. */\nexport interface TouchOptions {\n /** The rows were deleted rather than changed. */\n readonly removed?: boolean;\n}\n\n/**\n * `ctx.services`: in-process callers for the app's services (RFC 0003\n * sections 3 and 10), by service name: `ctx.services.projectService.get(input)`.\n * A call runs the whole pipeline (input check, access, handler, output\n * check) as the calling principal with transport `\"internal\"`, its writes\n * join the calling method's unit of work (one flush for both), and it is\n * cancelled with `ctx.signal`. Typed by the `contracts` of the app's types,\n * like `qd.caller`; untyped without them.\n */\nexport type ContextServices<T extends QuickdrawTypes = QuickdrawTypes> = CallerFor<T>;\n\nexport type { ContextRooms, Presence };\n\n/**\n * The fields of `ctx` the framework provides, whatever the app adds. `M` is\n * the type of `ctx.mcp`.\n */\nexport interface BaseContext<P = Principal, M = McpContext> {\n /**\n * Who is calling. `null` only in a `\"public\"` method called without\n * credentials; every other access form guarantees a principal.\n */\n readonly principal: P;\n /**\n * Aborts when the call is cancelled (a query whose callers all cancelled)\n * or runs past its time limit. Pass it to anything that can stop early.\n */\n readonly signal: AbortSignal;\n /** A logger bound to this call's service, method and request id. */\n readonly log: Logger;\n /** Identifies this call in logs and in its completion record. */\n readonly requestId: string;\n /** How the call arrived. */\n readonly transport: Transport;\n /**\n * The socket the call arrived on: its id, as the client socket's `id`,\n * `onRoomLeave`'s `socketId` and a channel handler's `ctx.socketId` name\n * it (a game keys a player's input by it). `undefined` for a call that\n * did not arrive over a socket: HTTP, MCP, in process, `ctx.services`. In\n * a method that shares its runs (`share`), the first caller's.\n */\n readonly socketId?: string;\n /**\n * The fields the MCP bridge's `context` option produced for this call, such\n * as the scopes of the agent's token; typed by `QuickdrawTypes[\"mcp\"]`.\n * `undefined` unless the call arrived over MCP.\n */\n readonly mcp?: M;\n /**\n * Records writes the tracked database client cannot see, raw SQL and\n * database cascades (RFC 0003 section 5.2), as if the client had made\n * them here: inside an open `db.$transaction` they join it and are dropped\n * on rollback. `target` is the model name (`\"task\"`); `removed` marks the\n * rows deleted. Does nothing when the dispatcher's `db` is not tracked.\n */\n touch(\n target: string | AnyContract,\n ids: string | readonly string[],\n options?: TouchOptions,\n ): void;\n /**\n * In-process callers for the app's services, as this call's principal:\n * `await ctx.services.projectService.get({ id })`. See {@link ContextServices}.\n */\n readonly services: ContextServices;\n /**\n * App-defined rooms the calling socket joins and leaves (`join` answers\n * `false` for a call without a socket), and typed room events: `emit` and\n * `emitToUser` (RFC 0003 section 12.5).\n */\n readonly rooms: ContextRooms;\n /** Who is online, when they were last seen, and who is in a room (RFC 0003 section 12.5). */\n readonly presence: Presence;\n}\n\n/**\n * A handler's `ctx`: the framework's fields plus the app's own from\n * `initQuickdraw({ context })`. An app field cannot replace a framework field.\n */\nexport type HandlerContext<T extends QuickdrawTypes, P = PrincipalOf<T>> = Omit<\n ContextExtensionOf<T>,\n keyof BaseContext\n> &\n Omit<BaseContext<P, McpContextOf<T>>, \"services\"> & {\n /** In-process callers for the app's services, typed by its `contracts`. */\n readonly services: ContextServices<T>;\n };\n\n/** What a handler receives: the parsed input, the call's context and the app's database client. */\nexport interface HandlerArgs<T extends QuickdrawTypes, Input, P = PrincipalOf<T>> {\n /** The input after its schema ran: defaults applied, transforms done. */\n readonly input: Input;\n readonly ctx: HandlerContext<T, P>;\n /** The database client given to the dispatcher, passed through unchanged. */\n readonly db: DbOf<T>;\n}\n\n/** Any handler's `ctx`, as the pipeline handles it. */\nexport type AnyContext = BaseContext<Principal | null>;\n\n/**\n * What `qd.run(fn)` and `dispatcher.run(fn)` give `fn`: the part of a\n * handler's `ctx` that means something outside a method call. A job has no\n * caller, so `principal` is `null`. A `fn` that takes no parameter still\n * works.\n *\n * @example\n * await qd.run(async (ctx) => {\n * const ids = await renumberWithSql(projectId);\n * ctx.touch(\"task\", ids);\n * });\n */\nexport interface RunContext {\n /** `ctx.touch`: records rows the tracked client cannot see (raw SQL, cascades) in this run's unit of work. */\n readonly touch: BaseContext[\"touch\"];\n /** The dispatcher's logger, bound to this run's request id. */\n readonly log: Logger;\n readonly principal: null;\n}\n\n/** Options of `qd.run(fn, options)` and `dispatcher.run(fn, options)`. */\nexport interface RunOptions {\n /**\n * Run `fn` in a unit of work of its own even inside a method call or a\n * transaction: for background work a handler starts and does not await\n * (a push sent after the reply, pruning what it reports dead). Its writes\n * flush once `fn` settles, on their own, instead of joining the handler's\n * unit, which may have flushed long before (they would then flush as\n * ambient writes, with a development warning). A failed flush is logged.\n * Default `false`: inside an open unit of work or transaction, `fn` joins\n * it.\n *\n * @example\n * // in a handler, not awaited: the reply does not wait for the push\n * void qd.run(() => sendPushes(db, message), { detached: true }).catch((error) => {\n * ctx.log.error(\"Pushing the message failed\", { error: String(error) });\n * });\n */\n readonly detached?: boolean;\n}\n\n/** Builds the app's fields of `ctx` from the framework's: the `context` option of `initQuickdraw`. */\nexport type ContextExtender = (base: AnyContext) => object;\n\n/**\n * What the framework's kits (RFC 0003 section 12) know about the call a\n * `ctx` belongs to: the service whose method runs, and the dispatcher's\n * access policies and storage adapter. A kit's handlers are made before any\n * dispatcher exists, so they find these through `kitRuntimeOf(ctx)`. It is\n * never a member of `ctx`.\n */\nexport interface KitRuntime {\n readonly service: AnyService;\n /** `dispatcher.access`, and `resolve` for levels without service grants (a collection scope's). */\n readonly access: DispatcherAccess & Pick<PolicyEngine, \"resolve\">;\n readonly storage: StorageAdapter | undefined;\n /** How many sockets sit in a room, for the admin kit's subscriber counts. */\n readonly occupancy?: RoomOccupancy;\n /**\n * The revision a read made from now on is no older than (the search\n * kit's pages): the process's last one, or behind a cluster's counter the\n * counter's.\n */\n readonly claimRevision?: () => number | Promise<number>;\n /**\n * Runs `fn` in a detached unit of work of the dispatcher, as\n * `qd.run(fn, { detached: true })` does: a kit's work after its call (the\n * admin kit's `onCommitted`), whose writes flush on their own.\n */\n readonly runDetached?: (fn: () => unknown) => Promise<unknown>;\n}\n\n/** The sockets in a room (RFC 0003 section 6), as this process sees its rooms. */\nexport interface RoomOccupancy {\n /** This process's sockets in `room`: none without a server. */\n sockets(room: string): number;\n /**\n * `true` when this process sees every socket: its server has no cluster\n * adapter (Redis), or there is no server.\n */\n complete(): boolean;\n}\n\n/**\n * The per-call fields the dispatcher fills in. `touch` is the dispatcher's\n * (its tracked writes), `rooms` and `presence` its live data's, `dispatch`\n * its own dispatch function, which `ctx.services` calls through; a context\n * built without them gets a `touch` that does nothing, `rooms` that join\n * nothing and send nothing, a `presence` that sees nobody, and `services`\n * that throw `INTERNAL`. `kit` is kept beside the context, never on it.\n */\nexport type ContextFields = Pick<\n AnyContext,\n \"principal\" | \"signal\" | \"log\" | \"requestId\" | \"transport\" | \"socketId\" | \"mcp\"\n> &\n Partial<Pick<AnyContext, \"touch\" | \"rooms\" | \"presence\">> & {\n readonly kit?: KitRuntime;\n readonly dispatch?: Dispatch;\n };\n\nconst KIT_RUNTIMES = new WeakMap<object, KitRuntime>();\nconst SERVICE_CALLERS = new WeakMap<object, (signal: AbortSignal) => ContextServices>();\n\n/**\n * The kit runtime of the call `ctx` belongs to, or `undefined` for a\n * context no dispatcher built.\n */\nexport function kitRuntimeOf(ctx: object): KitRuntime | undefined {\n return KIT_RUNTIMES.get(ctx);\n}\n\nfunction withRuntime<Ctx extends object>(\n ctx: Ctx,\n runtime: KitRuntime | undefined,\n services: ((signal: AbortSignal) => ContextServices) | undefined,\n): Ctx {\n if (runtime !== undefined) {\n KIT_RUNTIMES.set(ctx, runtime);\n }\n if (services !== undefined) {\n SERVICE_CALLERS.set(ctx, services);\n }\n return ctx;\n}\n\n/** A signal that never aborts, for calls that cannot be cancelled. */\nexport const NEVER_ABORTED: AbortSignal = new AbortController().signal;\n\nfunction notAvailable(member: string): QuickdrawError {\n return new QuickdrawError(\n \"INTERNAL\",\n `${member} needs a dispatcher: it calls through the dispatcher that runs the method`,\n );\n}\n\nfunction untracked(): void {\n // Without tracked writes there is nothing to record.\n}\n\n// Names that inspection, serialization and test matchers read from any\n// object. They answer `undefined` so logging a `ctx` never throws.\nconst INSPECTED = new Set([\n \"then\",\n \"toJSON\",\n \"constructor\",\n \"toString\",\n \"valueOf\",\n \"asymmetricMatch\",\n \"$$typeof\",\n \"nodeType\",\n]);\n\nfunction unavailable(member: string): ContextServices {\n return new Proxy(Object.freeze({}), {\n get(_target, key) {\n if (typeof key === \"symbol\" || INSPECTED.has(key)) {\n return undefined;\n }\n throw notAvailable(`${member}.${key}`);\n },\n });\n}\n\nconst SERVICES: ContextServices = unavailable(\"ctx.services\");\n\n/** The `ctx.rooms` of a context no dispatcher built: no socket to join with, no server to send through. */\nconst NO_ROOMS: ContextRooms = Object.freeze({\n join: () => false,\n leave: ((_room: string, target?: unknown) =>\n target === undefined ? false : Promise.resolve()) as ContextRooms[\"leave\"],\n emit: untracked,\n emitToUser: untracked,\n size: () => 0,\n});\n\n/** The `ctx.presence` of a context no dispatcher built: no server, so nobody is online. */\nconst NO_PRESENCE: Presence = Object.freeze({\n isOnline: () => Promise.resolve(false),\n lastSeen: () => Promise.resolve(null),\n count: () => Promise.resolve(0),\n users: () => Promise.resolve([]),\n});\n\n/**\n * `ctx.services` for a signal: callers acting as `principal` through\n * `dispatch`, every call cancelled with the signal.\n */\nfunction servicesOf(\n dispatch: Dispatch | undefined,\n principal: Principal | null,\n): ((signal: AbortSignal) => ContextServices) | undefined {\n if (dispatch === undefined) {\n return undefined;\n }\n return (signal) => createCaller(() => dispatch, principal, { signal }) as ContextServices;\n}\n\n/**\n * Builds a call's `ctx`: the framework's fields, then the app's fields from\n * `extend`. The framework's fields win when the names collide.\n */\nexport function createContext(fields: ContextFields, extend?: ContextExtender): AnyContext {\n const { kit, dispatch, ...own } = fields;\n const services = servicesOf(dispatch, own.principal);\n const base: AnyContext = Object.freeze({\n ...own,\n touch: own.touch ?? untracked,\n services: services?.(own.signal) ?? SERVICES,\n rooms: own.rooms ?? NO_ROOMS,\n presence: own.presence ?? NO_PRESENCE,\n });\n if (extend === undefined) {\n return withRuntime(base, kit, services);\n }\n return withRuntime(Object.freeze({ ...extend(base), ...base }), kit, services);\n}\n\n/**\n * The same `ctx` with another signal: the one a handler run aborts. Its\n * `ctx.services` calls are cancelled with that signal.\n */\nexport function withSignal(ctx: AnyContext, signal: AbortSignal): AnyContext {\n const services = SERVICE_CALLERS.get(ctx);\n const next =\n services === undefined ? { ...ctx, signal } : { ...ctx, signal, services: services(signal) };\n return withRuntime(Object.freeze(next), KIT_RUNTIMES.get(ctx), services);\n}\n"],"mappings":";;;;;;;;;;;;AAsEA,IAAM,gBAAgB,oBAAI,QAA8B;AAOjD,SAAS,gBAAgB,YAAoB,QAA4B;AAC9E,gBAAc,IAAI,YAAY,MAAM;AACtC;AAGO,SAAS,eAAe,YAA0D;AACvF,SAAO,eAAe,SAAY,SAAY,cAAc,IAAI,UAAU;AAC5E;AAYA,eAAe,OAAO,SAAyB,SAA4C;AACzF,QAAM,SAAS,MAAM,QAAQ,EAAE,OAAO;AACtC,MAAI,CAAC,OAAO,IAAI;AACd,UAAM,OAAO;AAAA,EACf;AACA,SAAO,OAAO,gBAAgB,OAAO,SAAY,OAAO;AAC1D;AAMO,SAAS,YAAoB,MAAwC;AAC1E,QAAM,OAAO,oBAAI,IAAoB;AACrC,SAAO,IAAI,MAAM,OAAO,OAAO,CAAC,CAAC,GAAG;AAAA,IAClC,IAAI,SAAS,MAAM;AACjB,UAAI,OAAO,SAAS,YAAY,SAAS,QAAQ;AAC/C,eAAO;AAAA,MACT;AACA,UAAI,SAAS,KAAK,IAAI,IAAI;AAC1B,UAAI,WAAW,QAAW;AACxB,iBAAS,KAAK,IAAI;AAClB,aAAK,IAAI,MAAM,MAAM;AAAA,MACvB;AACA,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AACH;AAGA,SAAS,YAAY,OAAgC,QAAiC;AACpF,MAAI,UAAU,UAAa,WAAW,QAAW;AAC/C,WAAO,SAAS;AAAA,EAClB;AACA,SAAO,YAAY,IAAI,CAAC,OAAO,MAAM,CAAC;AACxC;AAGA,SAAS,cAAc,WAA+B;AACpD,SAAO,UAAU,kBAAkB,UAAa,UAAU,kBAAkB;AAC9E;AAGA,eAAe,iBAAiB,WAAsB,QAA0C;AAC9F,MAAI;AACJ,MAAI;AACF,oBAAgB,MAAM,OAAO,KAAK,UAAU,MAAM;AAAA,EACpD,SAAS,OAAO;AACd,UAAM,UAAU,IAAI,eAAe,YAAY,gBAAgB;AAC/D,YAAQ,QAAQ;AAChB,UAAM;AAAA,EACR;AACA,SAAO,EAAE,GAAG,WAAW,eAAe,iBAAiB,CAAC,EAAE;AAC5D;AAYA,SAAS,iBACP,WACA,QACiB;AACjB,MAAI,cAAc,QAAQ,cAAc,SAAS,KAAK,WAAW,QAAW;AAC1E,WAAO,MAAM;AAAA,EACf;AAOA,MAAI;AACJ,SAAO,MAAM;AACX,UAAM,OAAO,OAAO;AACpB,QAAI,SAAS,QAAW;AACtB,aAAO;AAAA,IACT;AACA,UAAM,UAAU,KAAK,QAAQ;AAC7B,QAAI,MAAM,SAAS,QAAQ,KAAK,YAAY,SAAS;AACnD,aAAO,KAAK,UAAU,KAAK;AAAA,IAC7B;AACA,UAAM,QAAc,EAAE,MAAM,SAAS,SAAS,iBAAiB,WAAW,IAAI,EAAE;AAChF,WAAO;AACP,UAAM,QAAQ;AAAA,MACZ,CAAC,WAAW;AACV,cAAM,SAAS;AAAA,MACjB;AAAA,MACA,MAAM;AACJ,YAAI,SAAS,OAAO;AAClB,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AACA,WAAO,MAAM;AAAA,EACf;AACF;AAWO,SAAS,aACd,SACA,WACA,WAA2B,CAAC,GACpB;AACR,QAAM,kBAAkB,iBAAiB,WAAW,SAAS,MAAM;AACnE,SAAO;AAAA,IAAY,CAAC,YAClB,YAA4B,CAAC,WAAW,OAAO,OAAO,YAAY;AAChE,YAAM,QAAQ,gBAAgB;AAC9B,aAAO,MAAM,OAAO,SAAS;AAAA,QAC3B;AAAA,QACA;AAAA,QACA;AAAA;AAAA,QAEA,WAAW,iBAAiB,UAAU,MAAM,QAAQ;AAAA,QACpD,WAAW;AAAA,QACX,QAAQ,YAAY,SAAS,QAAQ,SAAS,MAAM;AAAA,MACtD,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;;;ACxNO,SAAS,iBAAiC;AAC/C,SAAO,IAAI,eAAe,aAAa,wBAAwB;AACjE;AAGO,SAAS,aAAa,WAAmC;AAC9D,SAAO,IAAI,eAAe,WAAW,uCAAuC,SAAS,KAAK;AAC5F;AAGO,SAAS,iBAAiB,QAAuC;AACtE,MAAI,QAAQ,YAAY,MAAM;AAC5B,UAAM,eAAe;AAAA,EACvB;AACF;AAMO,SAAS,WAAW,QAAqC;AAC9D,QAAM,SAAkB,OAAO;AAC/B,SAAO,kBAAkB,kBAAkB,OAAO,SAAS,YAAY,SAAS,eAAe;AACjG;AAEA,SAAS,YAAY,OAA4C;AAC/D,MAAI,EAAE,iBAAiB,UAAU,MAAM,SAAS,iCAAiC;AAC/E,WAAO;AAAA,EACT;AACA,QAAM,EAAE,KAAK,IAAI;AACjB,MAAI,SAAS,SAAS;AACpB,WAAO,IAAI,eAAe,YAAY,4BAA4B;AAAA,EACpE;AACA,MAAI,SAAS,SAAS;AACpB,WAAO,IAAI,eAAe,aAAa,kBAAkB;AAAA,EAC3D;AACA,SAAO;AACT;AAOO,SAAS,iBAAiB,OAAgC;AAC/D,MAAI,iBAAiB,kBAAkB,YAAY,MAAM,IAAI,GAAG;AAC9D,WAAO;AAAA,EACT;AACA,QAAM,SAAS,YAAY,KAAK,KAAK,IAAI,eAAe,YAAY,gBAAgB;AACpF,SAAO,QAAQ;AACf,SAAO;AACT;;;ACEA,IAAM,MAAa,OAAO,OAAO,EAAE,KAAK,MAAM,QAAQ,QAAW,OAAO,OAAU,CAAC;AAkBnF,SAAS,SAAS,OAAmC;AACnD,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAGA,SAAS,cAAc,OAA2D;AAChF,QAAM,YAAY,OAAO,eAAe,KAAK;AAC7C,SACE,cAAc,OAAO,aACrB,cAAc,QACd,OAAO,eAAe,SAAS,MAAM;AAEzC;AAGA,SAAS,OAAO,KAAa,MAAyB;AACpD,MAAI,QAAQ,KAAK;AACf,WAAO;AAAA,EACT;AACA,MAAI,CAAC,IAAI,WAAW,IAAI,GAAG;AACzB,WAAO;AAAA,EACT;AACA,MAAI,OAAgB;AACpB,aAAW,OAAO,IAAI,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG;AACzC,QAAI;AACJ,QAAI;AACF,aAAO,mBAAmB,GAAG,EAAE,WAAW,MAAM,GAAG,EAAE,WAAW,MAAM,GAAG;AAAA,IAC3E,QAAQ;AACN,aAAO;AAAA,IACT;AACA,WAAO,SAAS,IAAI,KAAK,OAAO,OAAO,MAAM,IAAI,IAAI,KAAK,IAAI,IAAI;AAAA,EACpE;AACA,SAAO;AACT;AAEA,IAAM,WAAW,CAAC,SAAS,SAAS,OAAO;AAE3C,SAAS,OAAO,MAAgB,UAAsC;AACpE,SAAO,SAAS,KAAK,CAAC,YAAY,KAAK,OAAO,MAAM,MAAS;AAC/D;AAEA,SAAS,QAAQ,MAAgD;AAC/D,QAAM,EAAE,KAAK,IAAI;AACjB,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO,CAAC,IAAI;AAAA,EACd;AACA,SAAO,MAAM,QAAQ,IAAI,IAAI,OAAO;AACtC;AAEA,SAAS,UAAU,QAAoC;AACrD,MAAI;AACF,WAAO,IAAI,OAAO,QAAQ,GAAG;AAAA,EAC/B,QAAQ;AACN,QAAI;AACF,aAAO,IAAI,OAAO,MAAM;AAAA,IAC1B,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAGA,SAAS,OAAO,OAAgC;AAC9C,QAAM,OAAO,oBAAI,IAAU;AAC3B,QAAM,UAAU,CAAC,GAAG,KAAK;AACzB,WAAS,OAAO,QAAQ,IAAI,GAAG,SAAS,QAAW,OAAO,QAAQ,IAAI,GAAG;AACvE,QAAI,CAAC,KAAK,IAAI,IAAI,GAAG;AACnB,WAAK,IAAI,IAAI;AACb,cAAQ,KAAK,GAAG,KAAK,OAAO;AAAA,IAC9B;AAAA,EACF;AACA,SAAO,CAAC,GAAG,IAAI;AACjB;AAOA,IAAM,WAAN,MAAe;AAAA,EAKb,YAA6B,MAAgB;AAAhB;AAAA,EAAiB;AAAA,EAJtC,OAAO;AAAA,EACE,QAAQ,oBAAI,IAAmB;AAAA,EAC/B,SAAS,oBAAI,IAAmB;AAAA,EAIzC,KAAK,KAAoB;AAC/B,SAAK,QAAQ;AACb,WAAO,EAAE,IAAI,KAAK,MAAM,KAAK,QAAQ,QAAW,OAAO,QAAW,SAAS,CAAC,EAAE;AAAA,EAChF;AAAA;AAAA,EAGA,KAAK,OAAsB;AACzB,QAAI,UAAU,UAAa,UAAU,MAAM;AACzC,aAAO,KAAK,KAAK,IAAI;AAAA,IACvB;AACA,QAAI,CAAC,SAAS,KAAK,GAAG;AAEpB,aAAO,KAAK,KAAK,KAAK;AAAA,IACxB;AACA,UAAM,QAAQ,KAAK,MAAM,IAAI,KAAK;AAClC,QAAI,UAAU,QAAW;AACvB,aAAO;AAAA,IACT;AACA,UAAM,OAAO,KAAK,KAAK,KAAK;AAC5B,SAAK,MAAM,IAAI,OAAO,IAAI;AAC1B,SAAK,YAAY,MAAM,KAAK;AAC5B,SAAK,UAAU,MAAM,KAAK;AAC1B,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,YAAY,MAAY,MAAsB;AACpD,UAAM,EAAE,KAAK,IAAI;AACjB,QAAI,OAAO,SAAS,UAAU;AAC5B,YAAM,SAAS,OAAO,MAAM,KAAK,IAAI;AACrC,WAAK,QAAQ,KAAK,WAAW,SAAY,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,MAAM,CAAC;AAAA,IAC9E;AACA,eAAW,WAAW,UAAU;AAC9B,YAAM,UAAU,KAAK,OAAO;AAC5B,UAAI,CAAC,MAAM,QAAQ,OAAO,GAAG;AAC3B;AAAA,MACF;AACA,iBAAW,UAAU,SAAS;AAC5B,cAAM,OAAO,KAAK,KAAK,MAAM;AAE7B,YAAI,EAAE,YAAY,WAAW,KAAK,OAAO,QAAQ,SAAS,IAAI;AAC5D,eAAK,QAAQ,KAAK,IAAI;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGQ,UAAU,MAAY,MAAsB;AAClD,UAAM,QAAQ,QAAQ,IAAI;AAC1B,UAAM,WAAW,KAAK,QAAQ,SAAS;AACvC,UAAM,iBAAiB,OAAO,MAAM;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AACD,UAAM,gBAAgB,OAAO,MAAM,CAAC,SAAS,eAAe,iBAAiB,CAAC;AAC9E,QAAI,gBAAgB;AAClB,WAAK,SAAS,KAAK,WAAW,IAAI;AAAA,IACpC,WAAW,CAAC,YAAY,OAAO,SAAS,QAAQ,MAAM,MAAM;AAE1D,WAAK,SAAS,EAAE,YAAY,oBAAI,IAAI,GAAG,UAAU,CAAC,GAAG,YAAY,KAAK,KAAK,IAAI,EAAE;AAAA,IACnF;AACA,QAAI,eAAe;AACjB,WAAK,QAAQ,KAAK,UAAU,IAAI;AAAA,IAClC,WAAW,CAAC,YAAY,OAAO,SAAS,OAAO,MAAM,MAAM;AACzD,WAAK,QAAQ,EAAE,QAAQ,CAAC,GAAG,MAAM,KAAK,KAAK,IAAI,EAAE;AAAA,IACnD;AACA,UAAM,SAAS,UAAU,UAAa,OAAO,MAAM,CAAC,SAAS,MAAM,CAAC;AACpE,SAAK,MAAM,CAAC,YAAY,CAAC,kBAAkB,CAAC,iBAAiB,CAAC;AAAA,EAChE;AAAA,EAEQ,WAAW,MAA6C;AAC9D,UAAM,aAAa,oBAAI,IAAkB;AACzC,QAAI,SAAS,KAAK,UAAU,GAAG;AAC7B,iBAAW,CAAC,KAAK,MAAM,KAAK,OAAO,QAAQ,KAAK,UAAU,GAAG;AAC3D,mBAAW,IAAI,KAAK,KAAK,KAAK,MAAM,CAAC;AAAA,MACvC;AAAA,IACF;AACA,UAAM,WAA4C,CAAC;AACnD,QAAI,OAAO;AACX,QAAI,SAAS,KAAK,iBAAiB,GAAG;AACpC,iBAAW,CAAC,QAAQ,MAAM,KAAK,OAAO,QAAQ,KAAK,iBAAiB,GAAG;AACrE,cAAM,QAAQ,UAAU,MAAM;AAC9B,YAAI,UAAU,QAAW;AACvB,iBAAO;AAAA,QACT,OAAO;AACL,mBAAS,KAAK,EAAE,OAAO,MAAM,KAAK,KAAK,MAAM,EAAE,CAAC;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AACA,UAAM,EAAE,qBAAqB,IAAI;AACjC,QAAI;AACJ,QAAI,MAAM;AACR,mBAAa,KAAK,KAAK,IAAI;AAAA,IAC7B,WAAW,yBAAyB,QAAW;AAE7C,mBACE,KAAK,eAAe,UAAa,KAAK,sBAAsB,SACxD,KAAK,KAAK,IAAI,IACd;AAAA,IACR,OAAO;AACL,mBAAa,yBAAyB,QAAQ,SAAY,KAAK,KAAK,oBAAoB;AAAA,IAC1F;AACA,WAAO,EAAE,YAAY,UAAU,WAAW;AAAA,EAC5C;AAAA,EAEQ,UAAU,MAA4C;AAC5D,UAAM,EAAE,OAAO,aAAa,gBAAgB,IAAI;AAChD,QAAI,MAAM,QAAQ,KAAK,GAAG;AAExB,aAAO;AAAA,QACL,QAAQ,MAAM,IAAI,CAAC,SAAkB,KAAK,KAAK,IAAI,CAAC;AAAA,QACpD,MAAM,oBAAoB,QAAQ,SAAY,KAAK,KAAK,eAAe;AAAA,MACzE;AAAA,IACF;AACA,UAAM,SAAS,MAAM,QAAQ,WAAW,IACpC,YAAY,IAAI,CAAC,SAAkB,KAAK,KAAK,IAAI,CAAC,IAClD,CAAC;AACL,WAAO,EAAE,QAAQ,MAAM,UAAU,QAAQ,SAAY,KAAK,KAAK,KAAK,EAAE;AAAA,EACxE;AAAA;AAAA,EAGA,QAAQ,OAA+B;AACrC,UAAM,MAAM,OAAO,KAAK;AACxB,QAAI,IAAI,KAAK,CAAC,SAAS,KAAK,GAAG,GAAG;AAChC,aAAO;AAAA,IACT;AACA,UAAM,MAAM,IACT,IAAI,CAAC,SAAS,KAAK,EAAE,EACrB,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,EACpB,KAAK,GAAG;AACX,UAAM,QAAQ,KAAK,OAAO,IAAI,GAAG;AACjC,QAAI,UAAU,QAAW;AACvB,aAAO;AAAA,IACT;AAEA,UAAM,QAAe,EAAE,KAAK,OAAO,QAAQ,QAAW,OAAO,OAAU;AACvE,SAAK,OAAO,IAAI,KAAK,KAAK;AAC1B,UAAM,UAAU,IAAI,QAAQ,CAAC,SAAU,KAAK,WAAW,SAAY,CAAC,IAAI,CAAC,KAAK,MAAM,CAAE;AACtF,UAAM,SAAS,IAAI,QAAQ,CAAC,SAAU,KAAK,UAAU,SAAY,CAAC,IAAI,CAAC,KAAK,KAAK,CAAE;AACnF,UAAM,SAAS,QAAQ,WAAW,IAAI,SAAY,KAAK,cAAc,OAAO;AAC5E,UAAM,QAAQ,OAAO,WAAW,IAAI,SAAY,KAAK,aAAa,MAAM;AACxE,WAAO;AAAA,EACT;AAAA,EAEQ,cAAc,SAA8D;AAClF,UAAM,OAAO,IAAI,IAAI,QAAQ,QAAQ,CAAC,WAAW,CAAC,GAAG,OAAO,WAAW,KAAK,CAAC,CAAC,CAAC;AAC/E,UAAM,aAAa,uBAAO,OAAO,IAAI;AACrC,eAAW,OAAO,MAAM;AACtB,YAAM,QAAQ,QAAQ,QAAQ,CAAC,WAAW;AACxC,cAAM,WACJ,OAAO,WAAW,IAAI,GAAG,KACzB,OAAO,SAAS,KAAK,CAAC,EAAE,MAAM,MAAM,MAAM,KAAK,GAAG,CAAC,GAAG,QACtD,OAAO;AACT,eAAO,aAAa,SAAY,CAAC,IAAI,CAAC,QAAQ;AAAA,MAChD,CAAC;AACD,iBAAW,GAAG,IAAI,KAAK,QAAQ,KAAK;AAAA,IACtC;AACA,UAAM,WAAW,QAAQ;AAAA,MAAQ,CAAC,WAChC,OAAO,SAAS,IAAI,CAAC,EAAE,OAAO,KAAK,OAAO,EAAE,OAAO,OAAO,KAAK,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE;AAAA,IACnF;AACA,UAAM,aAAa,QAAQ;AAAA,MAAQ,CAAC,WAClC,OAAO,eAAe,SAAY,CAAC,IAAI,CAAC,OAAO,UAAU;AAAA,IAC3D;AACA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,YAAY,WAAW,WAAW,IAAI,SAAY,KAAK,QAAQ,UAAU;AAAA,IAC3E;AAAA,EACF;AAAA,EAEQ,aAAa,QAA2D;AAC9E,UAAM,SAAS,KAAK,IAAI,GAAG,OAAO,IAAI,CAAC,UAAU,MAAM,OAAO,MAAM,CAAC;AACrE,UAAM,KAAK,CAAC,UACV,OAAO,QAAQ,CAAC,UAAU;AACxB,YAAM,OAAO,QAAQ,MAAM,OAAO,SAAS,MAAM,OAAO,KAAK,IAAI,MAAM;AACvE,aAAO,SAAS,SAAY,CAAC,IAAI,CAAC,IAAI;AAAA,IACxC,CAAC;AACH,UAAM,SAAS,MAAM,KAAK,EAAE,OAAO,GAAG,CAAC,GAAG,UAAU,KAAK,QAAQ,GAAG,KAAK,CAAC,CAAC;AAC3E,UAAM,OAAO,OAAO,QAAQ,CAAC,UAAW,MAAM,SAAS,SAAY,CAAC,IAAI,CAAC,MAAM,IAAI,CAAE;AACrF,WAAO,EAAE,QAAQ,MAAM,KAAK,WAAW,IAAI,SAAY,KAAK,QAAQ,IAAI,EAAE;AAAA,EAC5E;AACF;AAGA,IAAM,UAAyB,uBAAO,SAAS;AAG/C,SAAS,OAAO,MAA+B,KAAa,OAAsB;AAChF,MAAI,QAAQ,aAAa;AACvB,WAAO,eAAe,MAAM,KAAK;AAAA,MAC/B;AAAA,MACA,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,cAAc;AAAA,IAChB,CAAC;AAAA,EACH,OAAO;AACL,SAAK,GAAG,IAAI;AAAA,EACd;AACF;AAEA,SAAS,WAAW,QAAqB,KAAgC;AACvE,QAAM,WAAW,OAAO,WAAW,GAAG;AACtC,MAAI,aAAa,QAAW;AAC1B,WAAO;AAAA,EACT;AACA,aAAW,EAAE,OAAO,MAAM,KAAK,OAAO,UAAU;AAC9C,QAAI,MAAM,KAAK,GAAG,GAAG;AACnB,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO,OAAO;AAChB;AAGA,SAAS,KAAK,OAA0B,MAAwB;AAC9D,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AACA,SAAO,MAAM,OAAO,OAAO,SAAS,YAAY,SAAS,OAAO,OAAO,OAAO,OAAO,IAAI;AAC3F;AAEA,SAAS,aACP,QACA,OACmC;AACnC,QAAM,OAAO,OAAO,KAAK,KAAK;AAC9B,MAAI;AACJ,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;AACnD,UAAM,MAAM,KAAK,KAAK;AACtB,UAAM,OAAO,MAAM,GAAG;AACtB,UAAM,OAAO,KAAK,WAAW,SAAY,SAAY,WAAW,QAAQ,GAAG,GAAG,IAAI;AAClF,QAAI,SAAS,QAAW;AACtB,UAAI,SAAS,MAAM;AACjB;AAAA,MACF;AACA,aAAO,CAAC;AACR,eAAS,UAAU,GAAG,UAAU,OAAO,WAAW,GAAG;AACnD,cAAM,OAAO,KAAK,OAAO;AACzB,eAAO,MAAM,MAAM,MAAM,IAAI,CAAC;AAAA,MAChC;AAAA,IACF;AACA,QAAI,SAAS,SAAS;AACpB,aAAO,MAAM,KAAK,IAAI;AAAA,IACxB;AAAA,EACF;AACA,SAAO,QAAQ;AACjB;AAEA,SAAS,YAAY,OAAc,OAA+C;AAChF,QAAM,EAAE,MAAM,IAAI;AAClB,MAAI;AACJ,WAAS,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GAAG;AACpD,UAAM,OAAgB,MAAM,KAAK;AACjC,UAAM,OAAO;AAAA,MACX,UAAU,SAAY,QAAQ,QAAQ,MAAM,OAAO,SAAS,MAAM,OAAO,KAAK,IAAI,MAAM;AAAA,MACxF;AAAA,IACF;AACA,QAAI,SAAS,QAAW;AACtB,UAAI,SAAS,MAAM;AACjB;AAAA,MACF;AACA,aAAO,MAAM,MAAM,GAAG,KAAK;AAAA,IAC7B;AACA,QAAI,SAAS,SAAS;AACpB,WAAK,KAAK,IAAI;AAAA,IAChB;AAAA,EACF;AACA,SAAO,QAAQ;AACjB;AAGA,SAAS,OAAO,OAAc,OAAwB;AACpD,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,YAAY,OAAO,KAAK;AAAA,EACjC;AACA,SAAO,cAAc,KAAK,IAAI,aAAa,MAAM,QAAQ,KAAK,IAAI;AACpE;AAGA,SAAS,SAAS,MAA0C;AAC1D,QAAM,QAAQ,oBAAI,IAAoB;AACtC,QAAM,OAAO,oBAAI,IAAW;AAC5B,QAAM,QAA4D,CAAC,EAAE,OAAO,MAAM,MAAM,GAAG,CAAC;AAC5F,WAAS,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GAAG;AACpD,UAAM,EAAE,OAAO,KAAK,IAAI,MAAM,KAAK;AACnC,QAAI,KAAK,IAAI,KAAK,GAAG;AACnB;AAAA,IACF;AACA,SAAK,IAAI,KAAK;AACd,QAAI,MAAM,WAAW,QAAW;AAC9B,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,OAAO,UAAU,GAAG;AAClE,YAAI,UAAU,QAAW;AACvB;AAAA,QACF;AACA,cAAM,KAAK,SAAS,KAAK,MAAM,GAAG,IAAI,IAAI,GAAG;AAC7C,YAAI,CAAC,MAAM,IAAI,GAAG,GAAG;AACnB,gBAAM,IAAI,KAAK,EAAE;AAAA,QACnB;AACA,cAAM,KAAK,EAAE,OAAO,OAAO,MAAM,GAAG,CAAC;AAAA,MACvC;AACA,iBAAW,EAAE,OAAO,MAAM,KAAK,MAAM,OAAO,UAAU;AACpD,cAAM,KAAK,EAAE,OAAO,OAAO,MAAM,GAAG,IAAI,KAAK,CAAC;AAAA,MAChD;AACA,UAAI,MAAM,OAAO,eAAe,QAAW;AACzC,cAAM,KAAK,EAAE,OAAO,MAAM,OAAO,YAAY,MAAM,GAAG,IAAI,KAAK,CAAC;AAAA,MAClE;AAAA,IACF;AACA,QAAI,MAAM,UAAU,QAAW;AAC7B,iBAAW,SAAS,MAAM,MAAM,QAAQ;AACtC,cAAM,KAAK,EAAE,OAAO,OAAO,MAAM,GAAG,IAAI,KAAK,CAAC;AAAA,MAChD;AACA,UAAI,MAAM,MAAM,SAAS,QAAW;AAClC,cAAM,KAAK,EAAE,OAAO,MAAM,MAAM,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC;AAAA,MAC3D;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAGA,IAAM,yBAAyB,OAAO,OAAO,EAAE,iBAAiB,MAAM,CAAC;AAOhE,SAAS,oBAAoB,QAAoD;AACtF,MAAI,CAAC,cAAc,MAAM,GAAG;AAC1B,WAAO;AAAA,EACT;AACA,MAAI;AACJ,MAAI;AACF,WAAO,OAAO,WAAW,EAAE,WAAW,OAAO;AAAA,MAC3C,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,CAAC,SAAS,IAAI,GAAG;AACnB,WAAO;AAAA,EACT;AACA,QAAM,WAAW,IAAI,SAAS,IAAI;AAClC,QAAM,OAAO,SAAS,QAAQ,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC;AACnD,MAAI;AACJ,SAAO,OAAO,OAAO;AAAA,IACnB,MAAM,CAAC,UAAmB,KAAK,MAAM,KAAK;AAAA,IAC1C,UAAU,MAAO,UAAU,SAAS,IAAI;AAAA,EAC1C,CAAC;AACH;;;ACtfA,SAAS,QAAQ,KAAmC;AAClD,MAAI,OAAO,QAAQ,UAAU;AAC3B,WAAO,IAAI,eAAe,IAAI,SAAS;AAAA,EACzC;AACA,SAAO;AACT;AAEA,SAAS,YAAY,SAAuC;AAC1D,SAAO,OAAO,YAAY,WAAW,QAAQ,QAAQ,GAAG,IAAI,QAAQ,OAAO;AAC7E;AAOO,SAAS,aAAa,QAAiD;AAC5E,SAAO,OAAO,IAAI,CAAC,WAAW;AAAA,IAC5B,OAAO,MAAM,QAAQ,CAAC,GAAG,IAAI,WAAW;AAAA,IACxC,SAAS,MAAM;AAAA,EACjB,EAAE;AACJ;AAGA,eAAsB,WACpB,QACA,OACA,OACkB;AAClB,QAAM,SAAS,MAAM,SAAS,QAAQ,KAAK;AAC3C,MAAI,OAAO,WAAW,QAAW;AAC/B,UAAM,IAAI,eAAe,cAAc,qBAAqB,KAAK,IAAI;AAAA,MACnE,QAAQ,aAAa,OAAO,MAAM;AAAA,IACpC,CAAC;AAAA,EACH;AACA,SAAO,OAAO;AAChB;AAEA,SAAS,cAAc,eAAqE;AAC1F,SAAO,OAAO,OAAO;AAAA,IACnB,aAAa,OAAO,OAAO,EAAE,SAAS,GAAG,QAAQ,aAAa,UAAU,cAAc,CAAC;AAAA,EACzF,CAAC;AACH;AAEA,SAAS,WAAW,OAA2C;AAC7D,SAAO;AAAA,IAAc,CAAC,UACpB,UAAU,OAAO,EAAE,MAAM,IAAI,MAAM,WAAW,EAAE,SAAS,KAAK;AAAA,EAChE;AACF;AAEA,SAAS,aAAa,OAA2C;AAC/D,SAAO,cAAc,OAAO,UAAU;AACpC,QAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,aAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,qBAAqB,MAAM,CAAC,EAAE,CAAC,EAAE;AAAA,IAChE;AACA,UAAM,UAAU,MAAM,QAAQ,IAAI,MAAM,IAAI,CAAC,SAAkB,SAAS,OAAO,IAAI,CAAC,CAAC;AACrF,UAAM,SAAS,QAAQ;AAAA,MAAQ,CAAC,QAAQ,WACrC,OAAO,UAAU,CAAC,GAAG,IAAI,CAAC,WAAW;AAAA,QACpC,SAAS,MAAM;AAAA,QACf,MAAM,CAAC,OAAO,GAAI,MAAM,QAAQ,CAAC,CAAE;AAAA,MACrC,EAAE;AAAA,IACJ;AACA,WAAO,OAAO,SAAS,IAAI,EAAE,OAAO,IAAI,EAAE,MAAM;AAAA,EAClD,CAAC;AACH;AAEA,SAAS,iBAAiB,UAAuB,YAAsC;AACrF,QAAM,QAAQ,eAAe,WAAW,SAAS,SAAS,SAAS,YAAY,UAAU;AACzF,MAAI,UAAU,QAAW;AACvB,UAAM,IAAI;AAAA,MACR,kBAAkB,SAAS,IAAI,wCAAwC,UAAU;AAAA,IACnF;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,eAAe,UAAuB,QAAwC;AAC5F,MAAI,iBAAiB,MAAM,GAAG;AAC5B,WAAO;AAAA,EACT;AACA,MAAI,OAAO,WAAW,UAAU;AAC9B,WAAO,iBAAiB,UAAU,MAAM;AAAA,EAC1C;AACA,QAAM,MAAM,iBAAiB,UAAU,OAAO,UAAU;AACxD,SAAO,OAAO,SAAS,aAAa,WAAW,GAAG,IAAI,aAAa,GAAG;AACxE;AAOO,SAAS,eAAe,QAAgD;AAC7E,SAAO,iBAAiB,MAAM,IAAI,oBAAoB,MAAM,IAAI;AAClE;AAGA,eAAsB,aACpB,QACA,OACkC;AAClC,QAAM,SAAS,MAAM,SAAS,QAAQ,KAAK;AAC3C,SAAO,OAAO,WAAW,SAAY,SAAY,aAAa,OAAO,MAAM;AAC7E;;;ACwGA,IAAM,eAAe,oBAAI,QAA4B;AACrD,IAAM,kBAAkB,oBAAI,QAA0D;AAM/E,SAAS,aAAa,KAAqC;AAChE,SAAO,aAAa,IAAI,GAAG;AAC7B;AAEA,SAAS,YACP,KACA,SACA,UACK;AACL,MAAI,YAAY,QAAW;AACzB,iBAAa,IAAI,KAAK,OAAO;AAAA,EAC/B;AACA,MAAI,aAAa,QAAW;AAC1B,oBAAgB,IAAI,KAAK,QAAQ;AAAA,EACnC;AACA,SAAO;AACT;AAGO,IAAM,gBAA6B,IAAI,gBAAgB,EAAE;AAEhE,SAAS,aAAa,QAAgC;AACpD,SAAO,IAAI;AAAA,IACT;AAAA,IACA,GAAG,MAAM;AAAA,EACX;AACF;AAEA,SAAS,YAAkB;AAE3B;AAIA,IAAM,YAAY,oBAAI,IAAI;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,YAAY,QAAiC;AACpD,SAAO,IAAI,MAAM,OAAO,OAAO,CAAC,CAAC,GAAG;AAAA,IAClC,IAAI,SAAS,KAAK;AAChB,UAAI,OAAO,QAAQ,YAAY,UAAU,IAAI,GAAG,GAAG;AACjD,eAAO;AAAA,MACT;AACA,YAAM,aAAa,GAAG,MAAM,IAAI,GAAG,EAAE;AAAA,IACvC;AAAA,EACF,CAAC;AACH;AAEA,IAAM,WAA4B,YAAY,cAAc;AAG5D,IAAM,WAAyB,OAAO,OAAO;AAAA,EAC3C,MAAM,MAAM;AAAA,EACZ,QAAQ,CAAC,OAAe,WACtB,WAAW,SAAY,QAAQ,QAAQ,QAAQ;AAAA,EACjD,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,MAAM,MAAM;AACd,CAAC;AAGD,IAAM,cAAwB,OAAO,OAAO;AAAA,EAC1C,UAAU,MAAM,QAAQ,QAAQ,KAAK;AAAA,EACrC,UAAU,MAAM,QAAQ,QAAQ,IAAI;AAAA,EACpC,OAAO,MAAM,QAAQ,QAAQ,CAAC;AAAA,EAC9B,OAAO,MAAM,QAAQ,QAAQ,CAAC,CAAC;AACjC,CAAC;AAMD,SAAS,WACP,UACA,WACwD;AACxD,MAAI,aAAa,QAAW;AAC1B,WAAO;AAAA,EACT;AACA,SAAO,CAAC,WAAW,aAAa,MAAM,UAAU,WAAW,EAAE,OAAO,CAAC;AACvE;AAMO,SAAS,cAAc,QAAuB,QAAsC;AACzF,QAAM,EAAE,KAAK,UAAU,GAAG,IAAI,IAAI;AAClC,QAAM,WAAW,WAAW,UAAU,IAAI,SAAS;AACnD,QAAM,OAAmB,OAAO,OAAO;AAAA,IACrC,GAAG;AAAA,IACH,OAAO,IAAI,SAAS;AAAA,IACpB,UAAU,WAAW,IAAI,MAAM,KAAK;AAAA,IACpC,OAAO,IAAI,SAAS;AAAA,IACpB,UAAU,IAAI,YAAY;AAAA,EAC5B,CAAC;AACD,MAAI,WAAW,QAAW;AACxB,WAAO,YAAY,MAAM,KAAK,QAAQ;AAAA,EACxC;AACA,SAAO,YAAY,OAAO,OAAO,EAAE,GAAG,OAAO,IAAI,GAAG,GAAG,KAAK,CAAC,GAAG,KAAK,QAAQ;AAC/E;AAMO,SAAS,WAAW,KAAiB,QAAiC;AAC3E,QAAM,WAAW,gBAAgB,IAAI,GAAG;AACxC,QAAM,OACJ,aAAa,SAAY,EAAE,GAAG,KAAK,OAAO,IAAI,EAAE,GAAG,KAAK,QAAQ,UAAU,SAAS,MAAM,EAAE;AAC7F,SAAO,YAAY,OAAO,OAAO,IAAI,GAAG,aAAa,IAAI,GAAG,GAAG,QAAQ;AACzE;","names":[]}
@@ -76,4 +76,4 @@ export {
76
76
  toWire,
77
77
  fromWire
78
78
  };
79
- //# sourceMappingURL=chunk-V3KNCTXJ.js.map
79
+ //# sourceMappingURL=chunk-4YO5H5ON.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/protocol/guards.ts","../src/protocol/errors.ts"],"sourcesContent":["// Shape checks shared by the protocol's hand-written guards. Internal: the\n// package root exports the guards built on these, not these.\n\n/** An object that is not an array or `null`: what a JSON object decodes to. */\nexport type UnknownRecord = { readonly [key: string]: unknown };\n\n/** True when `value` is an object that is not an array or `null`. */\nexport function isRecord(value: unknown): value is UnknownRecord {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** True when `value` is a non-empty string, as service and method names are. */\nexport function isName(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0;\n}\n","// Error codes and the error every failed call carries (RFC 0003 section 3).\n// In 4.1 a failed call answered `{ success: false, error, code? }`\n// (4.1 `src/shared/types.ts:88-90`), every thrown error became code 500\n// with its own message (4.1 `src/server/ServiceRegistry.ts:398-402`), and\n// the client rethrew it as `ServiceCallError` with that number\n// (4.1 `src/client/serviceError.ts:6`). In 5.0 a handler picks the code by\n// throwing `QuickdrawError`; the same code reaches the caller on every\n// transport, and the HTTP transport maps it to a status with `httpStatus`.\n\nimport { isRecord } from \"./guards\";\n\n/** Every code a call can fail with, in the order of RFC 0003 section 3. */\nexport const ERROR_CODES = Object.freeze([\n \"UNAUTHENTICATED\",\n \"FORBIDDEN\",\n \"NOT_FOUND\",\n \"CONFLICT\",\n \"VALIDATION\",\n \"RATE_LIMITED\",\n \"CANCELLED\",\n \"TIMEOUT\",\n \"INTERNAL\",\n] as const);\n\n/**\n * Why a call failed:\n *\n * - `UNAUTHENTICATED` (401): there is no principal.\n * - `FORBIDDEN` (403): access was denied.\n * - `NOT_FOUND` (404): an unknown service, method or row.\n * - `CONFLICT` (409): a unique or state conflict.\n * - `VALIDATION` (422): the input failed its schema; see {@link ValidationErrorData}.\n * - `RATE_LIMITED` (429): a limiter or a full queue; see {@link RateLimitedErrorData}.\n * - `CANCELLED` (499): the caller cancelled.\n * - `TIMEOUT` (504): the handler ran past its time limit.\n * - `INTERNAL` (500): anything else.\n */\nexport type ErrorCode = (typeof ERROR_CODES)[number];\n\nconst HTTP_STATUS: Readonly<Record<ErrorCode, number>> = Object.freeze({\n UNAUTHENTICATED: 401,\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n CONFLICT: 409,\n VALIDATION: 422,\n RATE_LIMITED: 429,\n CANCELLED: 499,\n TIMEOUT: 504,\n INTERNAL: 500,\n});\n\n/** The message every `INTERNAL` error carries on the wire, whatever was thrown. */\nexport const INTERNAL_MESSAGE = \"Internal error\";\n\n/** True when `value` is one of the error codes. */\nexport function isErrorCode(value: unknown): value is ErrorCode {\n return typeof value === \"string\" && Object.hasOwn(HTTP_STATUS, value);\n}\n\n/** The HTTP status for an error code, as the table in RFC 0003 section 3 gives it. */\nexport function httpStatus(code: ErrorCode): number {\n return HTTP_STATUS[code];\n}\n\n/** One problem with a call's input, in a `VALIDATION` error's `data.issues`. */\nexport interface WireIssue {\n /** Where the problem is, as object keys and array indexes; empty for the input itself. */\n readonly path: readonly (string | number)[];\n readonly message: string;\n}\n\n/** The `data` of a `VALIDATION` error. */\nexport interface ValidationErrorData {\n readonly issues: readonly WireIssue[];\n}\n\n/** The `data` of a `RATE_LIMITED` error. */\nexport interface RateLimitedErrorData {\n /** How long to wait before trying again, in milliseconds. */\n readonly retryAfterMs: number;\n}\n\n/**\n * The error a failed call carries. A handler throws it to choose the code the\n * caller sees; the client rejects with it. Anything else a handler throws\n * reaches the caller as `INTERNAL` with a generic message (see {@link toWire}).\n */\nexport class QuickdrawError extends Error {\n /** Why the call failed. */\n readonly code: ErrorCode;\n /**\n * Details for the caller, sent as JSON: `issues` for `VALIDATION`,\n * `retryAfterMs` for `RATE_LIMITED`. `INTERNAL` errors never send it.\n */\n readonly data: unknown;\n\n constructor(code: ErrorCode, message: string, data?: unknown) {\n super(message);\n this.name = \"QuickdrawError\";\n this.code = code;\n this.data = data;\n }\n}\n\n/** An error as it travels: the `e` of a failed acknowledgement. */\nexport interface WireError {\n readonly code: ErrorCode;\n readonly message: string;\n readonly data?: unknown;\n}\n\n/**\n * The wire form of whatever a call failed with. A `QuickdrawError` keeps its\n * code, message and data. Anything else, and every `INTERNAL` error, becomes\n * `{ code: \"INTERNAL\", message: \"Internal error\" }`: no stack, message or data\n * of an internal failure ever reaches the caller, so log the original first.\n */\nexport function toWire(error: unknown): WireError {\n if (!(error instanceof QuickdrawError) || error.code === \"INTERNAL\" || !isErrorCode(error.code)) {\n return { code: \"INTERNAL\", message: INTERNAL_MESSAGE };\n }\n return error.data === undefined\n ? { code: error.code, message: error.message }\n : { code: error.code, message: error.message, data: error.data };\n}\n\n/**\n * The `QuickdrawError` a wire error describes. A code this version does not\n * know becomes `INTERNAL`, keeping the message and data. A payload that is not\n * a wire error (not an object, or no string `message`) becomes a generic\n * `INTERNAL`. Either way the caller can branch on `code`.\n */\nexport function fromWire(payload: unknown): QuickdrawError {\n if (!isRecord(payload) || typeof payload.message !== \"string\") {\n return new QuickdrawError(\"INTERNAL\", INTERNAL_MESSAGE);\n }\n const code = isErrorCode(payload.code) ? payload.code : \"INTERNAL\";\n return new QuickdrawError(code, payload.message, payload.data);\n}\n"],"mappings":";AAOO,SAAS,SAAS,OAAwC;AAC/D,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAGO,SAAS,OAAO,OAAiC;AACtD,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS;AACrD;;;ACFO,IAAM,cAAc,OAAO,OAAO;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAU;AAiBV,IAAM,cAAmD,OAAO,OAAO;AAAA,EACrE,iBAAiB;AAAA,EACjB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,WAAW;AAAA,EACX,SAAS;AAAA,EACT,UAAU;AACZ,CAAC;AAGM,IAAM,mBAAmB;AAGzB,SAAS,YAAY,OAAoC;AAC9D,SAAO,OAAO,UAAU,YAAY,OAAO,OAAO,aAAa,KAAK;AACtE;AAGO,SAAS,WAAW,MAAyB;AAClD,SAAO,YAAY,IAAI;AACzB;AAyBO,IAAM,iBAAN,cAA6B,MAAM;AAAA;AAAA,EAE/B;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA,EAET,YAAY,MAAiB,SAAiB,MAAgB;AAC5D,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;AAeO,SAAS,OAAO,OAA2B;AAChD,MAAI,EAAE,iBAAiB,mBAAmB,MAAM,SAAS,cAAc,CAAC,YAAY,MAAM,IAAI,GAAG;AAC/F,WAAO,EAAE,MAAM,YAAY,SAAS,iBAAiB;AAAA,EACvD;AACA,SAAO,MAAM,SAAS,SAClB,EAAE,MAAM,MAAM,MAAM,SAAS,MAAM,QAAQ,IAC3C,EAAE,MAAM,MAAM,MAAM,SAAS,MAAM,SAAS,MAAM,MAAM,KAAK;AACnE;AAQO,SAAS,SAAS,SAAkC;AACzD,MAAI,CAAC,SAAS,OAAO,KAAK,OAAO,QAAQ,YAAY,UAAU;AAC7D,WAAO,IAAI,eAAe,YAAY,gBAAgB;AAAA,EACxD;AACA,QAAM,OAAO,YAAY,QAAQ,IAAI,IAAI,QAAQ,OAAO;AACxD,SAAO,IAAI,eAAe,MAAM,QAAQ,SAAS,QAAQ,IAAI;AAC/D;","names":[]}
@@ -22,11 +22,11 @@ import {
22
22
  reorderInput,
23
23
  unknownKeys,
24
24
  withId
25
- } from "./chunk-NKVWV3FL.js";
25
+ } from "./chunk-B2UQ27GH.js";
26
26
  import {
27
27
  ACCESS_LEVELS,
28
28
  isAccessLevel
29
- } from "./chunk-DEXRBC5F.js";
29
+ } from "./chunk-7QIY2DDX.js";
30
30
  import {
31
31
  isStandardSchema
32
32
  } from "./chunk-47AEXVDM.js";
@@ -513,4 +513,4 @@ export {
513
513
  sharingSpecOf,
514
514
  sharing
515
515
  };
516
- //# sourceMappingURL=chunk-FMOLH6PL.js.map
516
+ //# sourceMappingURL=chunk-5IC5VZ7T.js.map
@@ -28,4 +28,4 @@ export {
28
28
  CHANNEL_DEFAULT_RATE,
29
29
  isScopedStream
30
30
  };
31
- //# sourceMappingURL=chunk-3I7R3DZW.js.map
31
+ //# sourceMappingURL=chunk-5YRQ26LF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/contract/collections.ts","../src/contract/realtime.ts"],"sourcesContent":["// Collection declarations for a contract (RFC 0003 section 7.1). A collection\n// is the rows of one service grouped by a scope value. Membership is declared\n// (a scope column or a junction table, plus an equality filter), never\n// computed by a function, so the framework knows which writes can move a row.\n// This replaces 4.1's `defineCollection({ resolveScopeId, checkScopeAccess,\n// snapshot, toItem })`.\n\nimport type { AccessLevel } from \"./access\";\n\n/** Page size of a collection snapshot when the collection sets no `limit`. */\nexport const DEFAULT_COLLECTION_LIMIT = 100;\n\n/** Largest page a client may ask for when the collection sets no `maxLimit`. */\nexport const DEFAULT_COLLECTION_MAX_LIMIT = 500;\n\n/**\n * A scope that comes from a junction table instead of a column on the row:\n * the rows of `model` link an entry (`entry` holds the row's id) to a scope\n * value (`scope`). For example, a chat appears in each member's list through\n * `via({ model: \"chatMember\", entry: \"chatId\", scope: \"userId\" })`.\n */\nexport interface ViaScope<\n Model extends string = string,\n Entry extends string = string,\n Scope extends string = string,\n> {\n readonly kind: \"via\";\n readonly model: Model;\n readonly entry: Entry;\n readonly scope: Scope;\n /**\n * The item is computed from the junction (a member count): every junction\n * write sends its entry again, whole, to each scope that still holds it.\n * Without it a junction write only adds or removes the entry in the scope\n * it links, so a count over the junction goes stale everywhere else.\n */\n readonly refreshEntry?: boolean;\n}\n\n/** What `via(...)` takes: the junction model, its entry and scope columns, and `refreshEntry`. */\nexport interface ViaOptions<\n Model extends string = string,\n Entry extends string = string,\n Scope extends string = string,\n> {\n /** The junction model, as the database client names it: `\"chatMember\"`. */\n readonly model: Model;\n /** The junction column holding the entry's id: `\"chatId\"`. */\n readonly entry: Entry;\n /** The junction column holding the scope value: `\"userId\"`. */\n readonly scope: Scope;\n /**\n * Set when the item reads the junction, as a `memberCount` mapped from a\n * relation count does: a junction create, update or delete then sends the\n * entry again, as `updated`, to every scope that still holds it (one read\n * of the entry's item per flush). Default `false`: a junction write adds\n * or removes the entry for the scope it links, and nothing else.\n */\n readonly refreshEntry?: boolean;\n}\n\n/**\n * Declares a collection scope that comes from a junction table.\n *\n * @example\n * myChats: {\n * scope: via({ model: \"chatMember\", entry: \"chatId\", scope: \"userId\", refreshEntry: true }),\n * item: \"listItem\",\n * order: [[\"id\", \"asc\"]],\n * }\n */\nexport function via<\n const Model extends string,\n const Entry extends string,\n const Scope extends string,\n>(junction: ViaOptions<Model, Entry, Scope>): ViaScope<Model, Entry, Scope> {\n return Object.freeze({\n kind: \"via\",\n model: junction.model,\n entry: junction.entry,\n scope: junction.scope,\n ...(junction.refreshEntry === undefined ? {} : { refreshEntry: junction.refreshEntry }),\n });\n}\n\nexport type SortDirection = \"asc\" | \"desc\";\n\n/**\n * Sort columns for the keyset cursor, ending in `id` so every row has a\n * unique position: `[[\"ordinal\", \"asc\"], [\"id\", \"asc\"]]`.\n */\nexport type OrderBy<Column extends string = string> = readonly [\n ...(readonly [Column, SortDirection])[],\n readonly [\"id\", SortDirection],\n];\n\n/** Who a view is evaluated for, on the client. */\nexport interface Viewer {\n readonly userId: string;\n}\n\n/**\n * A view: a named pure predicate evaluated on the client over the index rows\n * of a scope (RFC 0003 section 7.5). `row` holds only `id` and the\n * collection's `index` fields, which the type enforces.\n */\nexport type ViewPredicate<Row> = (row: Row, who: Viewer) => boolean;\n\n/** The equality filter that decides membership, for example `{ archived: false }`. */\nexport interface CollectionWhere {\n readonly [column: string]: string | number | boolean | null;\n}\n\n/** Any collection of any contract, as `defineContract` stores it. */\nexport interface CollectionDef {\n /** A string column of the entity, or `via(...)` for a junction table. */\n readonly scope: string | ViaScope;\n /** The projection each item is sent as: `\"entity\"` or a named projection. */\n readonly item: string;\n /** Sort columns for the keyset cursor; the last one is `id`. */\n readonly order: OrderBy;\n /** Equality filter that decides membership. */\n readonly where?: CollectionWhere | undefined;\n /** Page size. Default {@link DEFAULT_COLLECTION_LIMIT}. */\n readonly limit?: number | undefined;\n /** Largest page a client may ask for. Default {@link DEFAULT_COLLECTION_MAX_LIMIT}. */\n readonly maxLimit?: number | undefined;\n /** Item fields sent for every member of the scope (RFC 0003 section 7.4). */\n readonly index?: readonly string[] | undefined;\n /** Named predicates over index rows. Requires `index`. */\n readonly views?: { readonly [view: string]: ViewPredicate<never> } | undefined;\n /** Level required on the scope's anchor row. Default `\"Read\"`, through the anchor's policy. */\n readonly access?: AccessLevel | undefined;\n}\n","// Streams, channels and typed room events in a contract (RFC 0003 section\n// 12.5). A stream is server-to-client append-only data a subscriber receives\n// with a seed of recent items; a channel is fire-and-forget client-to-server\n// input (cursors, typing) behind a per-socket token bucket; an event is a\n// typed custom frame a handler sends to a room. 4.1 declared channels on the\n// service class (4.1 `src/server/BaseService.ts:915-942`) and typed room\n// events through the augmentable `QuickdrawEventMap`; here all three live in\n// the contract, so the client is typed from it.\n//\n// Methods, collections, streams, channels and events share one namespace:\n// the client exposes each as `qd.<service>.<name>`.\n\nimport type { AccessLevel } from \"./access\";\nimport type { AnyContract } from \"./defineContract\";\nimport type { StandardSchemaV1 } from \"./standardSchema\";\n\n/** The `scope` of a stream with one feed for the whole service: the default. */\nexport const GLOBAL_STREAM = \"global\";\n\n/** The most items a stream may keep per scope as the seed for new subscribers. */\nexport const STREAM_MAX_SEED = 1000;\n\n/** A channel's sustained rate when it declares none: messages per second per socket. */\nexport const CHANNEL_DEFAULT_RATE = 30;\n\n/**\n * The app room a stream's subscriber must be in (`access: { room }`): the\n * room's name, `{ prefix }` for any room whose name starts with it, or for a\n * scoped stream a function of the scope (`(worldId) => \\`world:${worldId}\\``).\n */\nexport type StreamRoom = string | RoomPrefix | ((scope: string) => string | null | undefined);\n\n/**\n * Who may subscribe to a stream (RFC 0003 section 4.1's forms, as data). A\n * scoped stream's scope value is the row an `entry` or `scope` form is about:\n * `{ entry: L }` needs level `L` on the row of this service whose id is the\n * scope, `{ scope: L, of }` level `L` on that row of `of`'s service.\n * `{ room }` opens it to the sockets in an app room a method joined them to\n * (signed in or not), as a channel's `requires: { room }` does its messages:\n * a socket that leaves the room, or is taken out of it, leaves the feed too.\n * A stream that declares none is closed: no client may subscribe.\n */\nexport type StreamAccess =\n | \"public\"\n | \"authenticated\"\n | {\n readonly service: AccessLevel;\n readonly entry?: undefined;\n readonly scope?: undefined;\n readonly of?: undefined;\n readonly room?: undefined;\n }\n | {\n readonly entry: AccessLevel;\n readonly service?: AccessLevel;\n readonly scope?: undefined;\n readonly of?: undefined;\n readonly room?: undefined;\n }\n | {\n readonly scope: AccessLevel;\n readonly of: AnyContract;\n readonly service?: undefined;\n readonly entry?: undefined;\n readonly room?: undefined;\n }\n | {\n readonly room: StreamRoom;\n readonly service?: undefined;\n readonly entry?: undefined;\n readonly scope?: undefined;\n readonly of?: undefined;\n };\n\n/** A server-to-client stream of append-only items (RFC 0003 section 12.5). */\nexport interface StreamDef<Item extends StandardSchemaV1 = StandardSchemaV1> {\n /** One item's schema. Pushed items are checked against it before they are sent. */\n readonly item: Item;\n /**\n * What a scope value is (`\"taskId\"`): the stream has one feed per scope.\n * `\"global\"`, the default, makes one feed for the whole service.\n */\n readonly scope?: string;\n /**\n * How many of the latest items the server keeps per scope, in memory on\n * each process, and sends a new subscriber first. Default 0; at most 1,000.\n */\n readonly seed?: number;\n /** Send items volatile: dropped for a client whose connection is backed up. Default `false`. */\n readonly volatile?: boolean;\n /** Who may subscribe. Without it the stream is closed. */\n readonly access?: StreamAccess;\n}\n\n/**\n * Where a channel requirement finds its row id or scope value in the parsed\n * payload: the name of a key holding a string, or a function of the payload.\n */\nexport type PayloadSelector = string | ((payload: never) => string | null | undefined);\n\n/**\n * Any app room whose name starts with `prefix` (`{ prefix: \"world:\" }`, a\n * game of many worlds): the sending socket passes when it is in one, and\n * the channel's handler gets the one it matched as `ctx.room`, so the\n * payload need not repeat which room it is for.\n */\nexport interface RoomPrefix {\n readonly prefix: string;\n}\n\n/**\n * The app room a channel requirement names: the room itself (`\"world\"`, a\n * game's one world), a function of the parsed payload that returns it\n * (`(payload) => \\`lobby:${payload.lobbyId}\\``), or `{ prefix }`, any room\n * whose name starts with it (`{ prefix: \"world:\" }`). Unlike a\n * {@link PayloadSelector}, a string here is the room's name, not a payload\n * key. A name starting with `qd:` or `user:` is never an app room: a literal\n * one (or such a prefix) is refused when the contract is defined, and a\n * computed one drops the message.\n */\nexport type RoomSelector = string | ((payload: never) => string | null | undefined) | RoomPrefix;\n\n/**\n * What a channel message requires of the socket that sends it: a live\n * subscription (`qd:sub`) to the row of this service `entity` names, or\n * (`qd:col:sub`) to the scope of `collection` that `scope` names; or that\n * the socket is in the app room `room` names (or, for `{ prefix }`, in any\n * app room whose name starts with it), which a method called over that\n * same socket joined with `ctx.rooms.join` (a room another socket of the\n * user joined does not count, and a reconnected socket is in none until it\n * joins again). The handler gets the room that matched as `ctx.room`. Each\n * is checked in memory against the sending socket's own records, on the\n * node it is connected to. A message whose payload names none is dropped.\n */\nexport type ChannelRequires =\n | {\n readonly entity: PayloadSelector;\n readonly collection?: undefined;\n readonly scope?: undefined;\n readonly room?: undefined;\n }\n | {\n readonly collection: string;\n readonly scope: PayloadSelector;\n readonly entity?: undefined;\n readonly room?: undefined;\n }\n | {\n readonly room: RoomSelector;\n readonly entity?: undefined;\n readonly collection?: undefined;\n readonly scope?: undefined;\n };\n\n/** A client-to-server fire-and-forget channel (RFC 0003 section 12.5). */\nexport interface ChannelDef<Payload extends StandardSchemaV1 = StandardSchemaV1> {\n /** One message's schema. A message that fails it is dropped. */\n readonly payload: Payload;\n /** Messages one socket may send per second, sustained. Default 30. */\n readonly ratePerSecond?: number;\n /** How many messages one socket may send at once. Default twice `ratePerSecond`. */\n readonly burst?: number;\n /** What the sender must already be subscribed to, or the app room it must be in. */\n readonly requires?: ChannelRequires;\n}\n\n/** A typed custom room event, delivered as `qd:event` (RFC 0003 section 8.3). */\nexport interface EventDef<Payload extends StandardSchemaV1 = StandardSchemaV1> {\n readonly payload: Payload;\n}\n\n/** True when a stream has one feed per scope value; false for a global stream. */\nexport function isScopedStream(def: Pick<StreamDef, \"scope\">): boolean {\n return def.scope !== undefined && def.scope !== GLOBAL_STREAM;\n}\n"],"mappings":";AAUO,IAAM,2BAA2B;AAGjC,IAAM,+BAA+B;AA0DrC,SAAS,IAId,UAA0E;AAC1E,SAAO,OAAO,OAAO;AAAA,IACnB,MAAM;AAAA,IACN,OAAO,SAAS;AAAA,IAChB,OAAO,SAAS;AAAA,IAChB,OAAO,SAAS;AAAA,IAChB,GAAI,SAAS,iBAAiB,SAAY,CAAC,IAAI,EAAE,cAAc,SAAS,aAAa;AAAA,EACvF,CAAC;AACH;;;AClEO,IAAM,gBAAgB;AAGtB,IAAM,kBAAkB;AAGxB,IAAM,uBAAuB;AAqJ7B,SAAS,eAAe,KAAwC;AACrE,SAAO,IAAI,UAAU,UAAa,IAAI,UAAU;AAClD;","names":[]}
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  isRecord
3
- } from "./chunk-V3KNCTXJ.js";
3
+ } from "./chunk-4YO5H5ON.js";
4
4
 
5
5
  // src/version.ts
6
- var QUICKDRAW_VERSION = "5.0.0-rc.7";
6
+ var QUICKDRAW_VERSION = "5.0.0";
7
7
 
8
8
  // src/contract/names.ts
9
9
  function entityRoom(service, id, level) {
@@ -127,4 +127,4 @@ export {
127
127
  MAX_SUBSCRIBE_IDS,
128
128
  MAX_SCOPE_LENGTH
129
129
  };
130
- //# sourceMappingURL=chunk-DEXRBC5F.js.map
130
+ //# sourceMappingURL=chunk-7QIY2DDX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/version.ts","../src/contract/names.ts","../src/protocol/version.ts","../src/contract/access.ts"],"sourcesContent":["/** The published version of `@fitzzero/quickdraw-core`. Kept in step with package.json. */\nexport const QUICKDRAW_VERSION = \"5.0.0\";\n","// Room and event names for protocol v5 (RFC 0003 sections 6, 7 and 8). Ported\n// from the 4.1 room helpers (4.1 `src/shared/types.ts:364-405`), which were\n// plain template strings so shared code could name a room without holding a\n// service instance. The 5.0 rooms live under a `qd:` prefix so they never\n// collide with an app's own rooms; the per-user room keeps its 4.1 name.\n\nimport type { AccessLevel } from \"./access\";\n\n/**\n * The room for one entity at one access tier: `qd:e:{service}:{id}@{level}`.\n * A subscriber joins the room for its own level, so a frame is built once and\n * stripped once per occupied tier.\n */\nexport function entityRoom(service: string, id: string, level: AccessLevel): string {\n return `qd:e:${service}:${id}@${level}`;\n}\n\n/** The room for one scope of a collection: `qd:c:{service}:{collection}:{scope}`. */\nexport function collectionRoom(service: string, collection: string, scope: string): string {\n return `qd:c:${service}:${collection}:${scope}`;\n}\n\n/** The room for a watched topic of a service: `qd:t:{service}:{topic}`. */\nexport function topicRoom(service: string, topic: string): string {\n return `qd:t:${service}:${topic}`;\n}\n\n/**\n * The change topic of a whole service (RFC 0003 section 11.3): every flush\n * that changes one of its rows or collection scopes signals it.\n */\nexport const SERVICE_TOPIC = \"service\";\n\n/** The change topic of one scope of a collection: `{collection}:{scope}` (RFC 0003 section 11.3). */\nexport function collectionTopic(collection: string, scope: string): string {\n return `${collection}:${scope}`;\n}\n\n/**\n * The room of a stream's feed (RFC 0003 section 12.5):\n * `qd:s:{service}:{stream}:{scope}` for one scope of a scoped stream, and\n * `qd:s:{service}:{stream}` for a global stream. Stream names hold no colon.\n */\nexport function streamRoom(service: string, stream: string, scope?: string): string {\n return scope === undefined ? `qd:s:${service}:${stream}` : `qd:s:${service}:${stream}:${scope}`;\n}\n\n/** The room every authenticated socket of a user joins: `user:{userId}`, as in 4.1. */\nexport function userRoom(userId: string): string {\n return `user:${userId}`;\n}\n\n/**\n * The prefixes of the rooms the framework manages: entity, collection, topic\n * and stream rooms (`qd:`) and user rooms (`user:`). `ctx.rooms.join` refuses\n * them; a socket enters those rooms only through their authorized paths.\n */\nexport const RESERVED_ROOM_PREFIXES: readonly string[] = Object.freeze([\"qd:\", \"user:\"]);\n\n/**\n * The reserved prefix `room` starts with (`qd:` or `user:`), or `undefined`\n * when an app room may have that name.\n */\nexport function reservedRoomPrefix(room: string): string | undefined {\n return RESERVED_ROOM_PREFIXES.find((prefix) => room.startsWith(prefix));\n}\n\n/** Events a client sends to the server (RFC 0003 section 8.2). */\nexport const CLIENT_EVENTS = Object.freeze({\n /** A method call: `{ id, s, m, i, v? }`, answered by ack. */\n call: \"qd:call\",\n /** Cancels an in-flight call: `{ id }`. */\n cancel: \"qd:cancel\",\n /** Subscribes to entities by id, with the revisions held. */\n sub: \"qd:sub\",\n /** Unsubscribes from entities. */\n unsub: \"qd:unsub\",\n /** Subscribes to a collection scope, or resumes it from a revision. */\n collectionSub: \"qd:col:sub\",\n /** Unsubscribes from a collection scope. */\n collectionUnsub: \"qd:col:unsub\",\n /** Loads collection items by id. */\n collectionItems: \"qd:col:items\",\n /** Joins a watched topic: `{ s, topic }`. */\n watch: \"qd:watch\",\n /** Leaves a watched topic. */\n unwatch: \"qd:unwatch\",\n /** Subscribes to a stream and receives its seed. */\n streamSub: \"qd:stream:sub\",\n /** Unsubscribes from a stream. */\n streamUnsub: \"qd:stream:unsub\",\n /** A fire-and-forget channel message, sent volatile: `[s, channel, payload]`. */\n channel: \"qd:ch\",\n} as const);\n\n/** Events the server sends to a client (RFC 0003 section 8.3). */\nexport const SERVER_EVENTS = Object.freeze({\n /** The handshake reply: `{ protocol, server, limits, features, userId, serviceAccess }`. */\n hello: \"qd:hello\",\n /** Entity frames: full update, patch or removal. */\n entity: \"qd:e\",\n /** Collection deltas, batched per flush. */\n collection: \"qd:c\",\n /** A watched topic changed; the client invalidates its queries. */\n changed: \"qd:changed\",\n /** Access to a subscription was revoked. */\n revoked: \"qd:revoked\",\n /** Stream items. */\n stream: \"qd:stream\",\n /** Typed custom room events declared in a contract's `events`. */\n event: \"qd:event\",\n /** Who is in an app room the socket is in: the list on joining, then each user who joins or leaves. */\n presence: \"qd:presence\",\n /** Reconnect within a jitter window. */\n rotate: \"qd:rotate\",\n /** The user's service grants changed. */\n access: \"qd:access\",\n} as const);\n\n/** The name of an event a client sends. */\nexport type ClientEventName = (typeof CLIENT_EVENTS)[keyof typeof CLIENT_EVENTS];\n\n/** The name of an event the server sends. */\nexport type ServerEventName = (typeof SERVER_EVENTS)[keyof typeof SERVER_EVENTS];\n","// The protocol version and the connection handshake (RFC 0003 section 8.1).\n// A v5 client connects with `auth: { token, qd: { protocol: 5, client } }`.\n// The server answers with `qd:hello`, or refuses a client that names another\n// protocol with `PROTOCOL_MISMATCH` in the `connect_error` data, and one whose\n// authentication failed with `UNAUTHENTICATED` there. A client that sends no\n// `auth.qd` is a 4.x client, which only the legacy shim serves (section 8.5).\n// There is no capability negotiation: the version decides.\n\nimport type { AccessLevel } from \"../contract/access\";\nimport { isRecord } from \"./guards\";\n\n/** The wire protocol this package speaks. */\nexport const PROTOCOL_VERSION = 5;\n\n/** `auth.qd`: what a v5 client sends when it connects. */\nexport interface QdHandshake {\n /** The protocol the client speaks. The server refuses any but its own. */\n readonly protocol: number;\n /** The client package's version, for logs. */\n readonly client: string;\n}\n\n/** The Socket.IO `auth` a v5 client connects with. */\nexport interface HandshakeAuth {\n /** The session token the server's `authenticate` reads. */\n readonly token?: string;\n /** The protocol the client speaks. A client without it is a 4.x client (RFC 0003 section 8.5). */\n readonly qd: QdHandshake;\n}\n\n/**\n * True when `value` has the shape of `auth.qd`, whatever protocol it names.\n * Compare `protocol` with {@link PROTOCOL_VERSION} to decide whether to serve it.\n */\nexport function isQdHandshake(value: unknown): value is QdHandshake {\n return isRecord(value) && Number.isInteger(value.protocol) && typeof value.client === \"string\";\n}\n\n/** The code in the `connect_error` data of a connection refused for its protocol. */\nexport const PROTOCOL_MISMATCH = \"PROTOCOL_MISMATCH\";\n\n/**\n * The `data` of the error a server refuses a connection with when the client\n * speaks another protocol, or none. It is not an `ErrorCode`: no call failed.\n */\nexport interface ProtocolMismatch {\n readonly code: typeof PROTOCOL_MISMATCH;\n /** The protocol the server speaks. */\n readonly expected: number;\n}\n\n/** True when a `connect_error`'s `data` says the server speaks another protocol. */\nexport function isProtocolMismatch(value: unknown): value is ProtocolMismatch {\n return isRecord(value) && value.code === PROTOCOL_MISMATCH && Number.isInteger(value.expected);\n}\n\n/**\n * The `data` of the error a server refuses a connection with when\n * authenticating it failed: the app's `authenticate` threw, so the\n * credentials are bad or could not be checked. A client tells it apart from\n * {@link ProtocolMismatch} by `code`; reconnecting needs other credentials.\n */\nexport interface AuthenticationRefused {\n readonly code: \"UNAUTHENTICATED\";\n}\n\n/** True when a `connect_error`'s `data` says authenticating the connection failed. */\nexport function isAuthenticationRefused(value: unknown): value is AuthenticationRefused {\n return isRecord(value) && value.code === \"UNAUTHENTICATED\";\n}\n\n/** The most ids one `qd:sub` may name (RFC 0003 section 6), as `qd:hello` announces it. */\nexport const MAX_SUBSCRIBE_IDS = 500;\n\n/** The longest collection scope value or change topic a frame may name, in characters. */\nexport const MAX_SCOPE_LENGTH = 256;\n\n/**\n * Each socket's lane of subscription events (`qd:sub`, `qd:col:sub`,\n * `qd:col:items`, `qd:watch`; RFC 0003 section 8.2), as `qd:hello` announces it.\n */\nexport interface HelloSubscriptionLimits {\n /** Subscription events one socket may have running at once. */\n readonly maxInFlight: number;\n /** Subscription events one socket may have waiting; past that one fails with `RATE_LIMITED`. */\n readonly maxQueued: number;\n}\n\n/** The limits a server announces in `qd:hello`, so a client can stay inside them. */\nexport interface HelloLimits {\n /** Queries one socket may have running at once; more wait in a queue (RFC 0003 section 9). */\n readonly maxInFlightQueries: number;\n /** Queries one socket may have waiting; past that a query fails with `RATE_LIMITED`. */\n readonly maxQueuedQueries: number;\n /** Ids one `qd:sub` may name (RFC 0003 section 6). */\n readonly maxSubscribeIds: number;\n /**\n * A call's default time limit in milliseconds, after which it fails with\n * `TIMEOUT`. A v5 client waits this long plus 2 s for an answer, so a slow\n * call ends with the server's `TIMEOUT` rather than its own.\n */\n readonly callTimeoutMs: number;\n /** The socket's lane of subscription events. */\n readonly subscriptions: HelloSubscriptionLimits;\n}\n\n/**\n * `qd:hello`: the server's answer to a v5 handshake, sent once per\n * connection, after the socket's listeners are in place. It says who the\n * socket acts for, so a client knows its user without another call.\n */\nexport interface HelloFrame {\n /** The protocol the server speaks. */\n readonly protocol: typeof PROTOCOL_VERSION;\n /** The server package's version. */\n readonly server: string;\n /**\n * This server's id: random, new each time a server starts. A client that\n * reconnects to the same id came back after a blip, to another id to a\n * restarted server (a game's world and clock start over) or, behind a\n * cluster, to another node, each of which has its own.\n */\n readonly serverId: string;\n /** What a client must stay within. */\n readonly limits: HelloLimits;\n /** Names of optional server features that are on. Informational only. */\n readonly features: readonly string[];\n /** The user the socket acts for, or `null` when it is anonymous. */\n readonly userId: string | null;\n /**\n * The principal's service-wide grants when the socket connected, by\n * service name: `{ taskService: \"Admin\" }`. Empty for an anonymous socket\n * or a principal without grants. Later changes arrive as `qd:access`.\n */\n readonly serviceAccess: Readonly<Record<string, AccessLevel>>;\n}\n","// Access levels and access-control lists, unchanged from 4.1\n// (4.1 `src/shared/types.ts:7-14`). The level names are stored in app data\n// (`User.serviceAccess`, JSON access lists), so they never change.\n\nexport type AccessLevel = \"Public\" | \"Read\" | \"Moderate\" | \"Admin\";\n\n/** Every access level, lowest first. */\nexport const ACCESS_LEVELS: readonly AccessLevel[] = Object.freeze([\n \"Public\",\n \"Read\",\n \"Moderate\",\n \"Admin\",\n]);\n\n/** True when `value` is one of the four access level names. */\nexport function isAccessLevel(value: unknown): value is AccessLevel {\n return typeof value === \"string\" && (ACCESS_LEVELS as readonly string[]).includes(value);\n}\n\nexport type ACE = {\n userId: string;\n level: AccessLevel;\n};\n\nexport type ACL = ACE[];\n"],"mappings":";;;;;AACO,IAAM,oBAAoB;;;ACY1B,SAAS,WAAW,SAAiB,IAAY,OAA4B;AAClF,SAAO,QAAQ,OAAO,IAAI,EAAE,IAAI,KAAK;AACvC;AAGO,SAAS,eAAe,SAAiB,YAAoB,OAAuB;AACzF,SAAO,QAAQ,OAAO,IAAI,UAAU,IAAI,KAAK;AAC/C;AAGO,SAAS,UAAU,SAAiB,OAAuB;AAChE,SAAO,QAAQ,OAAO,IAAI,KAAK;AACjC;AAMO,IAAM,gBAAgB;AAGtB,SAAS,gBAAgB,YAAoB,OAAuB;AACzE,SAAO,GAAG,UAAU,IAAI,KAAK;AAC/B;AAOO,SAAS,WAAW,SAAiB,QAAgB,OAAwB;AAClF,SAAO,UAAU,SAAY,QAAQ,OAAO,IAAI,MAAM,KAAK,QAAQ,OAAO,IAAI,MAAM,IAAI,KAAK;AAC/F;AAGO,SAAS,SAAS,QAAwB;AAC/C,SAAO,QAAQ,MAAM;AACvB;AAOO,IAAM,yBAA4C,OAAO,OAAO,CAAC,OAAO,OAAO,CAAC;AAMhF,SAAS,mBAAmB,MAAkC;AACnE,SAAO,uBAAuB,KAAK,CAAC,WAAW,KAAK,WAAW,MAAM,CAAC;AACxE;AAGO,IAAM,gBAAgB,OAAO,OAAO;AAAA;AAAA,EAEzC,MAAM;AAAA;AAAA,EAEN,QAAQ;AAAA;AAAA,EAER,KAAK;AAAA;AAAA,EAEL,OAAO;AAAA;AAAA,EAEP,eAAe;AAAA;AAAA,EAEf,iBAAiB;AAAA;AAAA,EAEjB,iBAAiB;AAAA;AAAA,EAEjB,OAAO;AAAA;AAAA,EAEP,SAAS;AAAA;AAAA,EAET,WAAW;AAAA;AAAA,EAEX,aAAa;AAAA;AAAA,EAEb,SAAS;AACX,CAAU;AAGH,IAAM,gBAAgB,OAAO,OAAO;AAAA;AAAA,EAEzC,OAAO;AAAA;AAAA,EAEP,QAAQ;AAAA;AAAA,EAER,YAAY;AAAA;AAAA,EAEZ,SAAS;AAAA;AAAA,EAET,SAAS;AAAA;AAAA,EAET,QAAQ;AAAA;AAAA,EAER,OAAO;AAAA;AAAA,EAEP,UAAU;AAAA;AAAA,EAEV,QAAQ;AAAA;AAAA,EAER,QAAQ;AACV,CAAU;;;ACzGH,IAAM,mBAAmB;AAsBzB,SAAS,cAAc,OAAsC;AAClE,SAAO,SAAS,KAAK,KAAK,OAAO,UAAU,MAAM,QAAQ,KAAK,OAAO,MAAM,WAAW;AACxF;AAGO,IAAM,oBAAoB;AAa1B,SAAS,mBAAmB,OAA2C;AAC5E,SAAO,SAAS,KAAK,KAAK,MAAM,SAAS,qBAAqB,OAAO,UAAU,MAAM,QAAQ;AAC/F;AAaO,SAAS,wBAAwB,OAAgD;AACtF,SAAO,SAAS,KAAK,KAAK,MAAM,SAAS;AAC3C;AAGO,IAAM,oBAAoB;AAG1B,IAAM,mBAAmB;;;ACpEzB,IAAM,gBAAwC,OAAO,OAAO;AAAA,EACjE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGM,SAAS,cAAc,OAAsC;AAClE,SAAO,OAAO,UAAU,YAAa,cAAoC,SAAS,KAAK;AACzF;","names":[]}
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  buildCaller,
3
3
  methodKey
4
- } from "./chunk-KR7K4QEY.js";
4
+ } from "./chunk-X5CWPX7H.js";
5
5
  import {
6
6
  QuickdrawError,
7
7
  fromWire,
8
8
  isRecord
9
- } from "./chunk-V3KNCTXJ.js";
9
+ } from "./chunk-4YO5H5ON.js";
10
10
 
11
11
  // src/utils/formatting.ts
12
12
  function formatCurrency(value, currency = "USD", locale = "en-US") {
@@ -272,4 +272,4 @@ export {
272
272
  parseJWTPayload,
273
273
  createServerCaller
274
274
  };
275
- //# sourceMappingURL=chunk-6G663RIR.js.map
275
+ //# sourceMappingURL=chunk-B2P7AZ25.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/formatting.ts","../src/utils/navigation.ts","../src/utils/jwt.ts","../src/client/serverCaller.ts"],"sourcesContent":["// Display formatting, carried over unchanged from 4.1\n// (4.1 `src/client/utils/formatting.ts`) except that the `value == null`\n// checks are spelled out. Pure and DOM-free: the `./utils` entry exports them\n// for React server components as well as the browser.\n\n/**\n * Format a currency value for display.\n */\nexport function formatCurrency(\n value: string | number | null | undefined,\n currency = \"USD\",\n locale = \"en-US\",\n): string {\n if (value === null || value === undefined) return \"-\";\n const num = typeof value === \"string\" ? parseFloat(value) : value;\n if (isNaN(num)) return \"-\";\n return new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency,\n }).format(num);\n}\n\n/**\n * Format a number for display with optional decimal places.\n */\nexport function formatNumber(\n value: string | number | null | undefined,\n options?: Intl.NumberFormatOptions,\n locale = \"en-US\",\n): string {\n if (value === null || value === undefined) return \"-\";\n const num = typeof value === \"string\" ? parseFloat(value) : value;\n if (isNaN(num)) return \"-\";\n return new Intl.NumberFormat(locale, options).format(num);\n}\n\n/**\n * Format a date for display.\n */\nexport function formatDate(\n value: string | Date | null | undefined,\n options?: Intl.DateTimeFormatOptions,\n locale = \"en-US\",\n): string {\n if (!value) return \"-\";\n const date = typeof value === \"string\" ? new Date(value) : value;\n if (isNaN(date.getTime())) return \"-\";\n return date.toLocaleDateString(\n locale,\n options ?? {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n },\n );\n}\n\n/**\n * Format a date with time for display.\n */\nexport function formatDateTime(\n value: string | Date | null | undefined,\n options?: Intl.DateTimeFormatOptions,\n locale = \"en-US\",\n): string {\n if (!value) return \"-\";\n const date = typeof value === \"string\" ? new Date(value) : value;\n if (isNaN(date.getTime())) return \"-\";\n return date.toLocaleString(\n locale,\n options ?? {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n },\n );\n}\n\n/**\n * Truncate a string to a maximum length.\n */\nexport function truncate(value: string | null | undefined, maxLength = 50): string {\n if (!value) return \"-\";\n if (value.length <= maxLength) return value;\n return `${value.slice(0, maxLength - 3)}...`;\n}\n\n/**\n * Format a percentage for display.\n */\nexport function formatPercent(\n value: string | number | null | undefined,\n decimals = 1,\n locale = \"en-US\",\n): string {\n if (value === null || value === undefined) return \"-\";\n const num = typeof value === \"string\" ? parseFloat(value) : value;\n if (isNaN(num)) return \"-\";\n return new Intl.NumberFormat(locale, {\n style: \"percent\",\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n }).format(num / 100);\n}\n","// Navigation helpers, carried over unchanged from 4.1\n// (4.1 `src/client/utils/navigation.ts`). Pure and DOM-free: the `./utils`\n// entry exports them for React server components as well as the browser.\n\nexport interface NavItem {\n id: string;\n label: string;\n href: string;\n icon?: unknown;\n children?: NavItem[];\n defaultExpanded?: boolean;\n requireAuth?: boolean;\n dynamicChildren?: boolean;\n serviceName?: string;\n minAccessLevel?: string;\n}\n\nexport interface BreadcrumbItem {\n label: string;\n href: string;\n siblings?: { label: string; href: string }[];\n}\n\n/**\n * Find a nav item by its href (exact match, searching children recursively).\n */\nexport function findNavItemByHref(items: NavItem[], href: string): NavItem | undefined {\n for (const item of items) {\n if (item.href === href) return item;\n if (item.children) {\n const found = findNavItemByHref(item.children, href);\n if (found) return found;\n }\n }\n return undefined;\n}\n\n/**\n * Find the parent nav item containing a child with the given href.\n */\nexport function findParentNavItem(items: NavItem[], href: string): NavItem | undefined {\n for (const item of items) {\n if (item.children) {\n const childMatch = item.children.find((c) => c.href === href);\n if (childMatch) return item;\n const nested = findParentNavItem(item.children, href);\n if (nested) return nested;\n }\n }\n return undefined;\n}\n\n/**\n * Build breadcrumb items from a pathname using the provided navigation config.\n */\nexport function buildBreadcrumbs(pathname: string, navigation: NavItem[]): BreadcrumbItem[] {\n const breadcrumbs: BreadcrumbItem[] = [];\n\n if (pathname === \"/\") {\n breadcrumbs.push({\n label: \"Home\",\n href: \"/\",\n siblings: navigation\n .filter((item) => item.href === \"/\" || !item.requireAuth)\n .map((item) => ({ label: item.label, href: item.href })),\n });\n return breadcrumbs;\n }\n\n const segments = pathname.split(\"/\").filter(Boolean);\n let currentPath = \"\";\n\n for (const segment of segments) {\n currentPath += `/${segment}`;\n const navItem = findNavItemByHref(navigation, currentPath);\n\n if (navItem) {\n const parent = findParentNavItem(navigation, currentPath);\n const siblingItems = parent?.children ?? navigation;\n\n breadcrumbs.push({\n label: navItem.label,\n href: navItem.href,\n siblings: siblingItems.map((item) => ({\n label: item.label,\n href: item.href,\n })),\n });\n } else {\n breadcrumbs.push({\n label: segment,\n href: currentPath,\n });\n }\n }\n\n return breadcrumbs;\n}\n\n/**\n * Check if a route requires authentication by searching the navigation config.\n */\nexport function routeRequiresAuth(\n pathname: string,\n navigation: NavItem[],\n userMenuItems?: NavItem[],\n): boolean {\n const navItem = findNavItemByHref(navigation, pathname);\n if (navItem) return navItem.requireAuth ?? false;\n\n if (userMenuItems) {\n const userItem = findNavItemByHref(userMenuItems, pathname);\n if (userItem) return userItem.requireAuth ?? false;\n }\n\n const segments = pathname.split(\"/\").filter(Boolean);\n let currentPath = \"\";\n for (const segment of segments) {\n currentPath += `/${segment}`;\n const item = findNavItemByHref(navigation, currentPath);\n if (item?.requireAuth) return true;\n }\n\n return false;\n}\n","// Reading a JWT's payload without verifying it, carried over from 4.1\n// (4.1 `src/client/utils/auth.ts:29-63`). Pure and DOM-free (`atob` is a\n// global in browsers, Node and React Native), so the `./utils` entry exports\n// it for React server components too. The helpers that keep the token in\n// `localStorage` stay on `./client` (`../client/auth.ts`).\n//\n// A JWT's segments are base64url (RFC 7515): `-` and `_` where base64 has\n// `+` and `/`, and no padding. 4.1 handed them to `atob` as they were, which\n// refuses those characters and a length that is not a multiple of 4; here a\n// segment is turned into padded base64 first, and its bytes read as UTF-8.\n\nexport interface JWTPayload {\n userId: string;\n email?: string;\n}\n\n/** The text of a base64url segment: its bytes as UTF-8 where `TextDecoder` exists, else as Latin-1. */\nfunction decodeSegment(segment: string): string {\n const base64 = segment.replaceAll(\"-\", \"+\").replaceAll(\"_\", \"/\");\n const binary = atob(base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), \"=\"));\n if (typeof TextDecoder === \"undefined\") {\n return binary;\n }\n return new TextDecoder().decode(Uint8Array.from(binary, (char) => char.charCodeAt(0)));\n}\n\n/**\n * Parse JWT payload client-side (not verified, for display purposes only).\n */\nexport function parseJWTPayload(token: string): JWTPayload | null {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3 || !parts[1]) return null;\n\n const decoded = decodeSegment(parts[1]);\n const payload: unknown = JSON.parse(decoded);\n\n if (\n typeof payload === \"object\" &&\n payload !== null &&\n \"userId\" in payload &&\n typeof (payload as { userId: unknown }).userId === \"string\"\n ) {\n const typedPayload = payload as { userId: string; email?: string };\n return {\n userId: typedPayload.userId,\n email: typedPayload.email,\n };\n }\n return null;\n } catch {\n return null;\n }\n}\n","// Calls over the HTTP transport (RFC 0003 section 10), for code that has no\n// socket: React server components prefetching for hydration, route handlers,\n// scripts. `POST {url}/qd/{service}/{method}` with the input as the JSON body,\n// answered `{ ok: true, d }` or `{ ok: false, e }` (`server/transports/http.ts`).\n// Every request says `Content-Type: application/json`, even without a body:\n// the server refuses any other, so a cross-site page cannot call a method\n// with a user's session cookie without a CORS preflight.\n//\n// `prefetch` fills a TanStack `QueryClient` under the key the hooks read\n// (`keys.ts`), so `dehydrate` and `HydrationBoundary` hand the result to the\n// browser's `useQuery`.\n//\n// React-free and dependency-free (it uses the global `fetch`), so the\n// isomorphic `./utils` entry exports it: a module that begins with\n// \"use client\", as `./client` does, cannot be called from a server component.\n\nimport type { QueryClient } from \"@tanstack/react-query\";\nimport type { AnyContract } from \"../contract/defineContract\";\nimport type { ContractMap, InputOf, KindOf, MethodName, OutputOf } from \"../contract/infer\";\nimport { QuickdrawError, fromWire } from \"../protocol/errors\";\nimport { isRecord } from \"../protocol/guards\";\nimport { methodKey, type MethodQueryKey } from \"./keys\";\nimport { buildCaller, type MethodTarget } from \"./members\";\n\n/** Headers sent with every call, or a function that returns them for each call. */\nexport type ServerCallerHeaders = HeadersInit | (() => HeadersInit | Promise<HeadersInit>);\n\n/** Options of {@link createServerCaller}. */\nexport interface ServerCallerOptions {\n /** The server's URL: `\"http://api:4000\"`. */\n readonly url: string;\n /** The path the server serves calls under, as its `http.path`. Default `\"/qd\"`. */\n readonly path?: string;\n /**\n * Sent with every call: the credentials the server's `authenticate` reads,\n * such as the incoming request's `cookie` or an `authorization` bearer\n * token. `Content-Type` is always `application/json`.\n */\n readonly headers?: ServerCallerHeaders;\n /** The `fetch` to call with. Default: the global one. */\n readonly fetch?: typeof fetch;\n}\n\n/** Options of one HTTP call. */\nexport interface ServerCallOptions {\n /** Aborting it cancels the request; the call rejects with `CANCELLED`. */\n readonly signal?: AbortSignal;\n}\n\ntype InputArgs<C extends AnyContract, M extends MethodName<C>, Rest extends unknown[]> =\n undefined extends InputOf<C, M>\n ? [input?: InputOf<C, M>, ...rest: Rest]\n : [input: InputOf<C, M>, ...rest: Rest];\n\n/** A query of the server caller. */\nexport interface ServerQuery<C extends AnyContract, M extends MethodName<C>> {\n /** Calls the query; resolves with its data or rejects with its `QuickdrawError`. */\n call(...args: InputArgs<C, M, [options?: ServerCallOptions]>): Promise<OutputOf<C, M>>;\n /** The key the query's result is cached under, the one the client's hooks read. */\n key(...args: InputArgs<C, M, []>): MethodQueryKey<InputOf<C, M>>;\n /** Calls the query into `queryClient`, as `queryClient.prefetchQuery` does: it never rejects. */\n prefetch(queryClient: QueryClient, ...args: InputArgs<C, M, []>): Promise<void>;\n}\n\n/** A mutation of the server caller. */\nexport interface ServerMutation<C extends AnyContract, M extends MethodName<C>> {\n /** Calls the mutation; resolves with its data or rejects with its `QuickdrawError`. */\n call(...args: InputArgs<C, M, [options?: ServerCallOptions]>): Promise<OutputOf<C, M>>;\n}\n\n/** One method of the server caller, by its kind. */\nexport type ServerMethod<C extends AnyContract, M extends MethodName<C>> =\n KindOf<C, M> extends \"query\" ? ServerQuery<C, M> : ServerMutation<C, M>;\n\n/** The server caller of a map of contracts: `caller.task.get.call(input)`. */\nexport type ServerCaller<Contracts extends ContractMap> = {\n readonly [Key in keyof Contracts]: {\n readonly [M in MethodName<Contracts[Key]>]: ServerMethod<Contracts[Key], M>;\n };\n};\n\ninterface Settings {\n readonly endpoint: string;\n readonly headers: ServerCallerHeaders | undefined;\n readonly fetch: typeof fetch;\n}\n\nfunction settingsOf(options: ServerCallerOptions): Settings {\n if (typeof options.url !== \"string\" || options.url === \"\") {\n throw new TypeError(\"createServerCaller: url must be the server's URL\");\n }\n const path = (options.path ?? \"/qd\").replace(/^\\/+|\\/+$/g, \"\");\n const base = options.url.replace(/\\/+$/, \"\");\n const fetchImpl = options.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== \"function\") {\n throw new TypeError(\"createServerCaller: there is no global fetch; pass options.fetch\");\n }\n return {\n endpoint: path === \"\" ? base : `${base}/${path}`,\n headers: options.headers,\n fetch: fetchImpl,\n };\n}\n\nasync function headersOf(settings: Settings): Promise<Headers> {\n const given =\n typeof settings.headers === \"function\" ? await settings.headers() : settings.headers;\n const headers = new Headers(given);\n headers.set(\"content-type\", \"application/json\");\n return headers;\n}\n\nfunction withCause(error: QuickdrawError, cause: unknown): QuickdrawError {\n error.cause = cause;\n return error;\n}\n\nasync function readReply(response: Response, target: MethodTarget): Promise<unknown> {\n const name = `${target.service}.${target.method}`;\n let reply: unknown;\n try {\n reply = await response.json();\n } catch (error) {\n const message = `${name} answered HTTP ${response.status} without a JSON reply`;\n throw withCause(new QuickdrawError(\"INTERNAL\", message), error);\n }\n if (isRecord(reply) && reply.ok === true) {\n return reply.d;\n }\n if (isRecord(reply) && reply.ok === false) {\n throw fromWire(reply.e);\n }\n throw new QuickdrawError(\n \"INTERNAL\",\n `${name} answered HTTP ${response.status} with no call reply`,\n );\n}\n\nasync function post(\n settings: Settings,\n target: MethodTarget,\n input: unknown,\n signal: AbortSignal | undefined,\n): Promise<unknown> {\n const url = `${settings.endpoint}/${encodeURIComponent(target.service)}/${encodeURIComponent(target.method)}`;\n let response: Response;\n try {\n response = await settings.fetch(url, {\n method: \"POST\",\n headers: await headersOf(settings),\n body: input === undefined ? undefined : JSON.stringify(input),\n signal,\n });\n } catch (error) {\n if (signal?.aborted === true) {\n throw withCause(new QuickdrawError(\"CANCELLED\", \"The call was cancelled\"), error);\n }\n const message = `${target.service}.${target.method}: the HTTP request failed`;\n throw withCause(new QuickdrawError(\"INTERNAL\", message), error);\n }\n return readReply(response, target);\n}\n\nfunction memberOf(settings: Settings, target: MethodTarget): object {\n const callMethod = (input?: unknown, options?: ServerCallOptions): Promise<unknown> =>\n post(settings, target, input, options?.signal);\n if (target.kind !== \"query\") {\n return Object.freeze({ call: callMethod });\n }\n const key = (input?: unknown): MethodQueryKey => methodKey(target.service, target.method, input);\n return Object.freeze({\n call: callMethod,\n key,\n prefetch: (queryClient: QueryClient, input?: unknown): Promise<void> =>\n queryClient.prefetchQuery({\n queryKey: key(input),\n queryFn: ({ signal }) => post(settings, target, input, signal),\n }),\n });\n}\n\n/**\n * Creates a caller that calls the server's methods over HTTP:\n * `caller.task.get.call(input)`, and for queries `key(input)` and\n * `prefetch(queryClient, input)`. Use it where there is no socket, such as a\n * React server component; import it from `@fitzzero/quickdraw-core/utils`\n * there, since `./client` is client code.\n *\n * @example\n * const server = createServerCaller({ task }, {\n * url: process.env.API_URL,\n * headers: { cookie: (await cookies()).toString() },\n * });\n * const queryClient = new QueryClient();\n * await server.task.get.prefetch(queryClient, { id });\n * return <HydrationBoundary state={dehydrate(queryClient)}><Task id={id} /></HydrationBoundary>;\n */\nexport function createServerCaller<const Contracts extends ContractMap>(\n contracts: Contracts,\n options: ServerCallerOptions,\n): ServerCaller<Contracts> {\n const settings = settingsOf(options);\n return Object.freeze(\n buildCaller(\"createServerCaller\", contracts, (target) => memberOf(settings, target)),\n ) as ServerCaller<Contracts>;\n}\n"],"mappings":"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","names":[]}
@@ -1301,4 +1301,4 @@ export {
1301
1301
  adminSpecOf,
1302
1302
  admin
1303
1303
  };
1304
- //# sourceMappingURL=chunk-NKVWV3FL.js.map
1304
+ //# sourceMappingURL=chunk-B2UQ27GH.js.map