@fitzzero/quickdraw-core 5.1.2 → 5.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/README.md +793 -57
  2. package/dist/{admin-DWWrT1h6.d.ts → admin-CS7JB_UH.d.ts} +2 -2
  3. package/dist/{adminSchemas-D4bFKsrb.d.ts → adminSchemas-29cGgrg5.d.ts} +1 -1
  4. package/dist/{auth-DXiSJZaf.d.ts → auth-DtdYjrZ9.d.ts} +11 -7
  5. package/dist/{caller-BT-Mv4bD.d.ts → caller-BTwGl7vm.d.ts} +183 -15
  6. package/dist/chunk-2FDSKLBO.js +82 -0
  7. package/dist/chunk-2FDSKLBO.js.map +1 -0
  8. package/dist/{chunk-GSIPUNJL.js → chunk-64I6MYBC.js} +139 -792
  9. package/dist/chunk-64I6MYBC.js.map +1 -0
  10. package/dist/chunk-7473HK24.js +17 -0
  11. package/dist/chunk-7473HK24.js.map +1 -0
  12. package/dist/chunk-7Y5ROPXL.js +33 -0
  13. package/dist/chunk-7Y5ROPXL.js.map +1 -0
  14. package/dist/chunk-A2RBQD66.js +7 -0
  15. package/dist/chunk-A2RBQD66.js.map +1 -0
  16. package/dist/chunk-ASAMUGHG.js +651 -0
  17. package/dist/chunk-ASAMUGHG.js.map +1 -0
  18. package/dist/{chunk-B2P7AZ25.js → chunk-CYE4UBOB.js} +6 -4
  19. package/dist/chunk-CYE4UBOB.js.map +1 -0
  20. package/dist/chunk-DNP65TD5.js +832 -0
  21. package/dist/chunk-DNP65TD5.js.map +1 -0
  22. package/dist/{chunk-5CGO426C.js → chunk-GYLWEJHW.js} +5 -1
  23. package/dist/chunk-GYLWEJHW.js.map +1 -0
  24. package/dist/{chunk-AONAFOYU.js → chunk-I3JCFS7H.js} +25 -13
  25. package/dist/chunk-I3JCFS7H.js.map +1 -0
  26. package/dist/{chunk-X5CWPX7H.js → chunk-IIQ3WMJK.js} +13 -2
  27. package/dist/chunk-IIQ3WMJK.js.map +1 -0
  28. package/dist/{chunk-6K5BY47X.js → chunk-JVTONQFI.js} +1277 -277
  29. package/dist/chunk-JVTONQFI.js.map +1 -0
  30. package/dist/{chunk-RL4VKLBX.js → chunk-KKQANRLG.js} +2 -2
  31. package/dist/{chunk-RL4VKLBX.js.map → chunk-KKQANRLG.js.map} +1 -1
  32. package/dist/{chunk-GKH3LJ7N.js → chunk-MPQAT55F.js} +38 -205
  33. package/dist/chunk-MPQAT55F.js.map +1 -0
  34. package/dist/chunk-NX2V6SIL.js +202 -0
  35. package/dist/chunk-NX2V6SIL.js.map +1 -0
  36. package/dist/{chunk-7QCUX4TK.js → chunk-NZHA4TZD.js} +72 -175
  37. package/dist/chunk-NZHA4TZD.js.map +1 -0
  38. package/dist/{chunk-MBH6IDSM.js → chunk-OCZJ4EYV.js} +40 -17
  39. package/dist/chunk-OCZJ4EYV.js.map +1 -0
  40. package/dist/{chunk-RJ5I2VO3.js → chunk-PHCURHC7.js} +6 -6
  41. package/dist/chunk-PHCURHC7.js.map +1 -0
  42. package/dist/{chunk-4YO5H5ON.js → chunk-Q4OGQM5I.js} +4 -10
  43. package/dist/chunk-Q4OGQM5I.js.map +1 -0
  44. package/dist/chunk-QSU47XEX.js +13 -0
  45. package/dist/chunk-QSU47XEX.js.map +1 -0
  46. package/dist/{chunk-LCC7HNFP.js → chunk-RZXJTDH5.js} +2 -2
  47. package/dist/{chunk-Z2LZ7IZ7.js → chunk-SN3OZVEQ.js} +5 -31
  48. package/dist/chunk-SN3OZVEQ.js.map +1 -0
  49. package/dist/{chunk-Z5ILULF2.js → chunk-SQ5VUG77.js} +4 -3
  50. package/dist/{chunk-Z5ILULF2.js.map → chunk-SQ5VUG77.js.map} +1 -1
  51. package/dist/chunk-STH5DLQP.js +1192 -0
  52. package/dist/chunk-STH5DLQP.js.map +1 -0
  53. package/dist/{chunk-NMXYENH4.js → chunk-VZFJTKIW.js} +6 -6
  54. package/dist/{chunk-753VJIUP.js → chunk-X4ZU4QH5.js} +43 -9
  55. package/dist/chunk-X4ZU4QH5.js.map +1 -0
  56. package/dist/chunk-XD7SRDUY.js +188 -0
  57. package/dist/chunk-XD7SRDUY.js.map +1 -0
  58. package/dist/chunk-Z7I6SONO.js +825 -0
  59. package/dist/chunk-Z7I6SONO.js.map +1 -0
  60. package/dist/cli/quickdraw-docs.js +131 -113
  61. package/dist/cli/quickdraw-docs.js.map +1 -1
  62. package/dist/client/core.d.ts +387 -0
  63. package/dist/client/core.js +109 -0
  64. package/dist/client/core.js.map +1 -0
  65. package/dist/client/index.d.ts +30 -193
  66. package/dist/client/index.js +56 -217
  67. package/dist/client/index.js.map +1 -1
  68. package/dist/{clientTypes-hWcPUVS9.d.ts → clientTypes-CUUNJwWs.d.ts} +3 -3
  69. package/dist/{connection-CgijdGpT.d.ts → connection-2EeQ_Et0.d.ts} +16 -9
  70. package/dist/{createServer-Cp-Wk500.d.ts → createServer-Bx5HOcYK.d.ts} +37 -9
  71. package/dist/{createTestApp-BB_PkqQ7.d.ts → createTestApp-DAMANT79.d.ts} +36 -9
  72. package/dist/{envelope-DzWyIXjj.d.ts → envelope-BMBaxppV.d.ts} +200 -8
  73. package/dist/{http-DotQ5bj8.d.ts → http-YzLAar3w.d.ts} +15 -50
  74. package/dist/index.d.ts +7 -6
  75. package/dist/index.js +61 -28
  76. package/dist/index.js.map +1 -1
  77. package/dist/{infer-BmoZsL9a.d.ts → infer-Br62cnyW.d.ts} +39 -1
  78. package/dist/{metrics-DW80Exve.d.ts → metrics-CTVpw0gu.d.ts} +2 -2
  79. package/dist/parser.js +2 -1
  80. package/dist/prisma/index.d.ts +13 -6
  81. package/dist/prisma/index.js +155 -9
  82. package/dist/prisma/index.js.map +1 -1
  83. package/dist/remote-N7OUAGOW.js +15 -0
  84. package/dist/remote-N7OUAGOW.js.map +1 -0
  85. package/dist/server/auth/index.d.ts +3 -3
  86. package/dist/server/auth/index.js +5 -3
  87. package/dist/server/auth/index.js.map +1 -1
  88. package/dist/server/index.d.ts +140 -36
  89. package/dist/server/index.js +162 -55
  90. package/dist/server/index.js.map +1 -1
  91. package/dist/server/mcp/index.d.ts +34 -18
  92. package/dist/server/mcp/index.js +29 -12
  93. package/dist/server/mcp/index.js.map +1 -1
  94. package/dist/server/otel.d.ts +3 -3
  95. package/dist/{sharing-UDLn1049.d.ts → sharing-BrsmlDv_.d.ts} +3 -3
  96. package/dist/testing/client.d.ts +13 -13
  97. package/dist/testing/client.js +17 -10
  98. package/dist/testing/client.js.map +1 -1
  99. package/dist/testing/index.d.ts +49 -12
  100. package/dist/testing/index.js +102 -19
  101. package/dist/testing/index.js.map +1 -1
  102. package/dist/testing/mock.d.ts +5 -5
  103. package/dist/testing/mock.js +15 -9
  104. package/dist/tracked-BR5b2O-U.d.ts +43 -0
  105. package/dist/{types-CYliTP65.d.ts → types-CLRCQGnO.d.ts} +4 -3
  106. package/dist/types-tMagHbjy.d.ts +151 -0
  107. package/dist/utils/index.d.ts +16 -4
  108. package/dist/utils/index.js +6 -3
  109. package/package.json +5 -1
  110. package/dist/chunk-4YO5H5ON.js.map +0 -1
  111. package/dist/chunk-5CGO426C.js.map +0 -1
  112. package/dist/chunk-6K5BY47X.js.map +0 -1
  113. package/dist/chunk-753VJIUP.js.map +0 -1
  114. package/dist/chunk-7QCUX4TK.js.map +0 -1
  115. package/dist/chunk-AONAFOYU.js.map +0 -1
  116. package/dist/chunk-B2P7AZ25.js.map +0 -1
  117. package/dist/chunk-GKH3LJ7N.js.map +0 -1
  118. package/dist/chunk-GSIPUNJL.js.map +0 -1
  119. package/dist/chunk-MBH6IDSM.js.map +0 -1
  120. package/dist/chunk-RJ5I2VO3.js.map +0 -1
  121. package/dist/chunk-X5CWPX7H.js.map +0 -1
  122. package/dist/chunk-Z2LZ7IZ7.js.map +0 -1
  123. /package/dist/{chunk-LCC7HNFP.js.map → chunk-RZXJTDH5.js.map} +0 -0
  124. /package/dist/{chunk-NMXYENH4.js.map → chunk-VZFJTKIW.js.map} +0 -0
@@ -1,5 +1,5 @@
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-BmoZsL9a.js';
2
- import { d as ListSort, c as ListQuery, b as ListPage, D as AdminWritable, 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-D4bFKsrb.js';
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-Br62cnyW.js';
2
+ import { d as ListSort, c as ListQuery, b as ListPage, D as AdminWritable, 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-29cGgrg5.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>;
@@ -1,4 +1,4 @@
1
- import { z as SortDirection, A as AccessLevel } from './infer-BmoZsL9a.js';
1
+ import { z as SortDirection, A as AccessLevel } from './infer-Br62cnyW.js';
2
2
 
3
3
  /** `list`'s page size when the caller gives none. */
4
4
  declare const LIST_DEFAULT_LIMIT = 50;
@@ -1,7 +1,7 @@
1
1
  import { IncomingMessage, IncomingHttpHeaders } from 'node:http';
2
2
  import { Socket } from 'socket.io';
3
- import { A as AccessLevel } from './infer-BmoZsL9a.js';
4
- import { P as Principal, M as MaybePromise } from './types-CYliTP65.js';
3
+ import { A as AccessLevel } from './infer-Br62cnyW.js';
4
+ import { P as Principal, M as MaybePromise } from './types-CLRCQGnO.js';
5
5
 
6
6
  /**
7
7
  * A request as Express leaves it: maybe with `body` from `express.json()`,
@@ -80,11 +80,15 @@ type AuthenticateResult<P extends Principal> = P | ({
80
80
  interface ServerAuth<P extends Principal = Principal> {
81
81
  /**
82
82
  * Says who is calling. Throwing refuses the socket connection ("Authentication
83
- * failed", with `{ code: "UNAUTHENTICATED" }` as the `connect_error` data) or
84
- * answers the HTTP call with `UNAUTHENTICATED`; returning nothing lets the
85
- * caller in anonymously, so only `"public"` methods pass. Throw a
86
- * `QuickdrawError("UNAUTHENTICATED", ...)` for a refusal that is the
87
- * caller's doing (it logs at debug; anything else thrown logs at error).
83
+ * failed") or answers the HTTP call with `UNAUTHENTICATED`; returning
84
+ * nothing lets the caller in anonymously, so only `"public"` methods pass.
85
+ * Throw a `QuickdrawError("UNAUTHENTICATED", ...)` (or `"FORBIDDEN"`) for a
86
+ * refusal that is the caller's doing: it logs at debug, and a socket's
87
+ * `connect_error` data is `{ code: "UNAUTHENTICATED" }`, which signs a
88
+ * client out. Anything else thrown is the server's failure (its session
89
+ * store down, say): it logs at error, and the data is `{ code: "INTERNAL" }`,
90
+ * which a client retries, keeping the user, so never throw a plain `Error`
91
+ * for bad credentials.
88
92
  * On an HTTP call a thrown `QuickdrawError("FORBIDDEN", ...)` is answered
89
93
  * as it is, with 403 (logged at debug): a credential the request may not
90
94
  * use from where it came, as `socketAuth` answers a session cookie sent
@@ -1,7 +1,7 @@
1
- import { ad as Version, a5 as Revision } from './envelope-DzWyIXjj.js';
1
+ import { A as AccessLevel, J as AnyContract, y as CollectionWhere, O as OrderBy, k as MethodKind, d as StandardSchemaV1, ag as EventName, ah as EventPayloadOf, aB as ServerChannelName, ab as ChannelPayloadOf, aa as ChannelName, aC as ServerStreamName, az as StreamName, am as IsScopedStream, ay as StreamItemOf, ae as ContractMap, ap as MethodName, al as InputOf, ar as OutputOf } from './infer-Br62cnyW.js';
2
+ import { P as Principal, Q as QuickdrawTypes, M as MaybePromise, b as PrincipalOf, a as McpContext, T as Transport, C as ContextExtensionOf, c as McpContextOf, D as DbOf } from './types-CLRCQGnO.js';
2
3
  import { L as Logger } from './logger-Yz93KzdV.js';
3
- import { A as AccessLevel, J as AnyContract, y as CollectionWhere, O as OrderBy, k as MethodKind, d as StandardSchemaV1, ag as EventName, ah as EventPayloadOf, aa as ChannelName, ab as ChannelPayloadOf, az as StreamName, am as IsScopedStream, ay as StreamItemOf, ae as ContractMap, ap as MethodName, al as InputOf, ar as OutputOf } from './infer-BmoZsL9a.js';
4
- import { P as Principal, Q as QuickdrawTypes, M as MaybePromise, c as PrincipalOf, a as McpContext, T as Transport, C as ContextExtensionOf, b as McpContextOf, D as DbOf } from './types-CYliTP65.js';
4
+ import { aA as Version, as as Revision } from './envelope-BMBaxppV.js';
5
5
 
6
6
  /** What a development warning is about. */
7
7
  type DevWarningKind = "n-plus-one" | "unbounded-read" | "oversized-response" | "nested-write" | "ambient-write" | "batch-read" | "batch-create-many" | "repeated-call" | "tiered-field-in-output" | "resolver-without-reads" | "untracked-access-model" | "shared-principal" | "channel-without-requires";
@@ -368,6 +368,14 @@ interface ServiceCollection {
368
368
  readonly access: AccessLevel;
369
369
  /** The contract of the rows scope values are ids of; `undefined` for a `"self"` scope. */
370
370
  readonly anchor: AnyContract | undefined;
371
+ /**
372
+ * The service-wide grant on the collection's service every subscriber needs
373
+ * besides the anchor or self check (`requires: { service: L }`);
374
+ * `undefined` for none.
375
+ */
376
+ readonly requires: {
377
+ readonly service: AccessLevel;
378
+ } | undefined;
371
379
  /** More changed rows than this for one scope in one flush go out as one `reset`. */
372
380
  readonly bulkThreshold: number;
373
381
  /**
@@ -523,6 +531,8 @@ interface Service<T extends QuickdrawTypes = QuickdrawTypes, C extends AnyContra
523
531
  * rooms. `undefined` when the service declares none.
524
532
  */
525
533
  readonly onRoomLeave: RoomLeaveHandler | undefined;
534
+ /** The service's own `onHostLeave`: `createServer` runs it, beside the server's own, when a room's host leaves. */
535
+ readonly onHostLeave?: HostLeaveHandler | undefined;
526
536
  /** Type-only: the app types the service was defined with. Never set. */
527
537
  readonly "~types"?: T;
528
538
  }
@@ -660,6 +670,21 @@ interface RowAccess {
660
670
  allows(form: EntryAccess | ScopeAccess, request: AccessRequest): MaybePromise<boolean>;
661
671
  }
662
672
 
673
+ /**
674
+ * A row whose access may have changed: who may now see more or less of it.
675
+ * `id` is the row (the anchor subscriptions record); without it, any row of
676
+ * the service. `userId` is the user whose level may have changed; without it,
677
+ * anyone's.
678
+ */
679
+ interface AccessChange {
680
+ /** The service name. */
681
+ readonly service: string;
682
+ readonly id?: string;
683
+ readonly userId?: string;
684
+ }
685
+ /** Receives access changes; a promise it returns is awaited before the flush moves on. */
686
+ type AccessChangeListener = (change: AccessChange) => void | PromiseLike<void>;
687
+
663
688
  /**
664
689
  * Who is online and who is in a room (RFC 0003 section 12.5): `ctx.presence`,
665
690
  * `server.presence`, `qd.presence`. Every answer is a promise: on a server
@@ -739,6 +764,19 @@ interface ServerRooms {
739
764
  * it is 0.
740
765
  */
741
766
  size(room: string): number;
767
+ /**
768
+ * The host of app room `room` (host mode, RFC 0003 section 12.5): the id
769
+ * of the socket that serves the room's host-served channels and streams,
770
+ * or `null` when it has none. This node's record, which every node of a
771
+ * cluster keeps. Room names are checked as `join` checks them.
772
+ */
773
+ hostOf(room: string): string | null;
774
+ /**
775
+ * Leaves app room `room` without a host, on every node: its sockets hear
776
+ * `qd:host [room, null]`. Nothing happens for a room without one, and
777
+ * `onHostLeave` does not run (the host did not leave).
778
+ */
779
+ clearHost(room: string): void;
742
780
  }
743
781
  /**
744
782
  * `ctx.rooms` (RFC 0003 sections 3, 12.5 and 15): app-defined rooms the
@@ -762,6 +800,20 @@ interface ContextRooms extends ServerRooms {
762
800
  join(room: string): boolean;
763
801
  /** Takes the calling socket out of an app room; `false` when it was not in it, or the call has no socket. */
764
802
  leave(room: string): boolean;
803
+ /**
804
+ * Makes the calling socket the host of app room `room` (host mode, RFC
805
+ * 0003 section 12.5): the room's sockets hear `qd:host [room, socketId]`
806
+ * on every node, and so does every socket that joins it later, until the
807
+ * host leaves the room (`onHostLeave` runs), another socket is made its
808
+ * host, or `clearHost` runs. Its peers then send the room's host-served
809
+ * channels to it and subscribe to its host-served streams over peer links.
810
+ * Returns `false`, doing nothing, for a call that did not arrive over a
811
+ * socket. The socket must be in the room (`FORBIDDEN`) and signed in
812
+ * (`UNAUTHENTICATED`), and the server must serve peer links
813
+ * (`createServer({ peers: true })`, else `INTERNAL`). Room names are
814
+ * checked as `join` checks them.
815
+ */
816
+ setHost(room: string): boolean;
765
817
  /** See {@link ServerRooms.leave}: every socket of the user, on every node, from any call. */
766
818
  leave(room: string, target: RoomTarget): Promise<void>;
767
819
  }
@@ -805,10 +857,31 @@ interface RoomLeave<P = Principal> {
805
857
  * error it throws is logged; a server's `close()` waits for it.
806
858
  */
807
859
  type RoomLeaveHandler<P = Principal> = (leave: RoomLeave<P>, ctx: RunContext) => void | PromiseLike<void>;
860
+ /** The host of an app room left it (host mode): what `onHostLeave` hears. */
861
+ interface HostLeave<P = Principal> {
862
+ readonly room: string;
863
+ /** The host socket that left. */
864
+ readonly socketId: string;
865
+ /** Its principal. */
866
+ readonly principal: P | null;
867
+ /** Its own leave, a removal, or a disconnect. */
868
+ readonly reason: RoomLeaveReason;
869
+ }
870
+ /**
871
+ * `onHostLeave` (a service's, beside `onRoomLeave`, and `createServer`'s):
872
+ * called once when the host of an app room leaves it, is taken out of it or
873
+ * disconnects, on the node that held it, after the room heard
874
+ * `qd:host [room, null]`, in a unit of work of its own. The room has no
875
+ * host until a method sets one again: the app decides what follows (another
876
+ * host, the end of the game).
877
+ */
878
+ type HostLeaveHandler<P = Principal> = (leave: HostLeave<P>, ctx: RunContext) => void | PromiseLike<void>;
808
879
  /** The arguments of a stream's `push`: `(scope, item)` for a scoped stream, `(item)` for a global one. */
809
880
  type StreamPushArgs<C extends AnyContract, K extends StreamName<C>> = IsScopedStream<C, K> extends true ? [scope: string, item: StreamItemOf<C, K>] : [item: StreamItemOf<C, K>];
810
881
  /** The arguments of a stream's `pushMany`: `(scope, items)` for a scoped stream, `(items)` for a global one. */
811
882
  type StreamPushManyArgs<C extends AnyContract, K extends StreamName<C>> = IsScopedStream<C, K> extends true ? [scope: string, items: readonly StreamItemOf<C, K>[]] : [items: readonly StreamItemOf<C, K>[]];
883
+ /** The arguments of a stream's `subscribers`: `(scope)` for a scoped stream, `()` for a global one. */
884
+ type StreamSubscribersArgs<C extends AnyContract, K extends StreamName<C>> = IsScopedStream<C, K> extends true ? [scope: string] : [];
812
885
  /** What `qd.stream(contract, name)` returns. */
813
886
  interface StreamHandle<C extends AnyContract, K extends StreamName<C>> {
814
887
  /**
@@ -825,6 +898,19 @@ interface StreamHandle<C extends AnyContract, K extends StreamName<C>> {
825
898
  * with nothing kept or sent. The batch form of a `push` in a loop.
826
899
  */
827
900
  pushMany(...args: StreamPushManyArgs<C, K>): void;
901
+ /**
902
+ * How many sockets subscribe to the feed (`subscribers(scope)`, or
903
+ * `subscribers()` for a global stream), on every node, anonymous ones
904
+ * included: a job skips the work nobody watches. These are the sockets in
905
+ * the feed's room, the ones a push reaches: a subscribe counts from when it
906
+ * joins the feed, once it is authorized. Behind a cluster adapter the
907
+ * other nodes answer one request with a count each: an answer that does
908
+ * not arrive within `cluster.timeoutMs` counts as 0, and so does a node
909
+ * of an earlier version, which does not know the request. A host-served stream (`serve: "host"`) has no feed on
910
+ * the server, so, as for `push`, its handle refuses this with a
911
+ * `TypeError`: only the host's client knows who subscribes.
912
+ */
913
+ subscribers(...args: StreamSubscribersArgs<C, K>): Promise<number>;
828
914
  }
829
915
  /**
830
916
  * What a stream's `seed` function receives besides the scope: who is
@@ -886,7 +972,7 @@ type StreamValidation = "always" | "development";
886
972
  * subset): a seed computed at subscribe time, and when items are checked.
887
973
  */
888
974
  type StreamOptions<T extends QuickdrawTypes, C extends AnyContract> = {
889
- readonly [K in StreamName<C>]?: StreamImplementation<T, C, K>;
975
+ readonly [K in ServerStreamName<C>]?: StreamImplementation<T, C, K>;
890
976
  };
891
977
  /** A stream's `seed` function as the subscribe path calls it, whatever its declared types. */
892
978
  type AnyStreamSeed = (scope: string | undefined, ctx: StreamSeedContext) => unknown;
@@ -936,12 +1022,15 @@ type ChannelRoomOf<C extends AnyContract, K extends ChannelName<C>> = C["channel
936
1022
  readonly room: string | object;
937
1023
  };
938
1024
  } ? string : undefined;
939
- /** `defineService`'s `channels`: one implementation per channel of the contract. */
1025
+ /**
1026
+ * `defineService`'s `channels`: one implementation per channel of the
1027
+ * contract the server handles (a host-served one takes none).
1028
+ */
940
1029
  type ChannelOptions<T extends QuickdrawTypes, C extends AnyContract> = {
941
- readonly [K in ChannelName<C>]: ChannelImplementation<T, ChannelPayloadOf<C, K>, ChannelRoomOf<C, K>>;
1030
+ readonly [K in ServerChannelName<C>]: ChannelImplementation<T, ChannelPayloadOf<C, K>, ChannelRoomOf<C, K>>;
942
1031
  };
943
1032
  /** `{ channels }` is required when the contract declares channels: every message needs a handler. */
944
- type ChannelsRequired<C extends AnyContract> = [ChannelName<C>] extends [never] ? unknown : {
1033
+ type ChannelsRequired<C extends AnyContract> = [ServerChannelName<C>] extends [never] ? unknown : {
945
1034
  readonly channels: unknown;
946
1035
  };
947
1036
  /**
@@ -1032,6 +1121,8 @@ interface ServiceStream {
1032
1121
  readonly access: AccessForm | undefined;
1033
1122
  /** The contract's `access: { room }`: the app room a subscriber's socket must be in. */
1034
1123
  readonly room: StreamRoomAccess | undefined;
1124
+ /** True for a stream the room's host pushes (`serve: "host"`): the server neither pushes nor subscribes it. */
1125
+ readonly host: boolean;
1035
1126
  }
1036
1127
  /** A stream's `access: { room }`, compiled: the app room a subscriber's socket must be in. */
1037
1128
  type StreamRoomAccess = {
@@ -1054,10 +1145,10 @@ interface TouchOptions {
1054
1145
  * `ctx.services`: in-process callers for the app's services (RFC 0003
1055
1146
  * sections 3 and 10), by service name: `ctx.services.projectService.get(input)`.
1056
1147
  * A call runs the whole pipeline (input check, access, handler, output
1057
- * check) as the calling principal with transport `"internal"`, its writes
1058
- * join the calling method's unit of work (one flush for both), and it is
1059
- * cancelled with `ctx.signal`. Typed by the `contracts` of the app's types,
1060
- * like `qd.caller`; untyped without them.
1148
+ * check) as the calling principal with transport `"internal"` and the
1149
+ * calling method's `ctx.mcp`, its writes join the calling method's unit of
1150
+ * work (one flush for both), and it is cancelled with `ctx.signal`. Typed by
1151
+ * the `contracts` of the app's types, like `qd.caller`; untyped without them.
1061
1152
  */
1062
1153
  type ContextServices<T extends QuickdrawTypes = QuickdrawTypes> = CallerFor<T>;
1063
1154
 
@@ -1094,7 +1185,10 @@ interface BaseContext<P = Principal, M = McpContext> {
1094
1185
  /**
1095
1186
  * The fields the MCP bridge's `context` option produced for this call, such
1096
1187
  * as the scopes of the agent's token; typed by `QuickdrawTypes["mcp"]`.
1097
- * `undefined` unless the call arrived over MCP.
1188
+ * `undefined` unless the call arrived over MCP or was made through the
1189
+ * `ctx.services` of a call that has it (nested calls too), which passes
1190
+ * the same object on. Such a call's `transport` is `"internal"`: to tell a
1191
+ * token's call apart, read `ctx.mcp`, not `ctx.transport`.
1098
1192
  */
1099
1193
  readonly mcp?: M;
1100
1194
  /**
@@ -1106,10 +1200,20 @@ interface BaseContext<P = Principal, M = McpContext> {
1106
1200
  */
1107
1201
  touch(target: string | AnyContract, ids: string | readonly string[], options?: TouchOptions): void;
1108
1202
  /**
1109
- * In-process callers for the app's services, as this call's principal:
1110
- * `await ctx.services.projectService.get({ id })`. See {@link ContextServices}.
1203
+ * In-process callers for the app's services, as this call's principal and
1204
+ * with its `ctx.mcp`: `await ctx.services.projectService.get({ id })`. See
1205
+ * {@link ContextServices}.
1111
1206
  */
1112
1207
  readonly services: ContextServices;
1208
+ /**
1209
+ * The caller's levels on rows of the app's services, as the access forms
1210
+ * count them (RFC 0003 section 4.3): `dispatcher.access` bound to
1211
+ * `ctx.principal`, with the grants this call runs with. For a `custom`
1212
+ * form that checks a row its key names only sometimes, or a parent its
1213
+ * input names: `await ctx.access.can(project, input.projectId, "Moderate")`.
1214
+ * See {@link ContextAccess}.
1215
+ */
1216
+ readonly access: ContextAccess;
1113
1217
  /**
1114
1218
  * App-defined rooms the calling socket joins and leaves (`join` answers
1115
1219
  * `false` for a call without a socket), and typed room events: `emit` and
@@ -1317,6 +1421,70 @@ interface FlushSink {
1317
1421
  onFlushError?(writes: readonly WriteRecord[], info: FlushInfo, error: unknown): void | Promise<void>;
1318
1422
  }
1319
1423
 
1424
+ /** The dispatcher's view of its services' access policies: `dispatcher.access`. */
1425
+ interface DispatcherAccess {
1426
+ /**
1427
+ * The principal's level on each of `ids` of `service`, as an `{ entry }`
1428
+ * check counts it: the service's policy, or `Admin` on every row when the
1429
+ * principal holds a service-wide `Admin` grant and the service keeps
1430
+ * `adminBypass` on. A grant below `Admin` does not count. A row that is
1431
+ * not found has no level. One batched lookup per policy.
1432
+ */
1433
+ levelsFor(service: AnyContract | string, principal: Principal, ids: readonly string[]): Promise<RowLevels>;
1434
+ /**
1435
+ * A filter for `db.<model>.findMany({ where })` matching exactly the rows of
1436
+ * `service` on which `levelsFor` gives the principal at least `level`:
1437
+ * `{}` (every row) for a service-wide `Admin` with `adminBypass`, or
1438
+ * `"none"` when no row matches.
1439
+ */
1440
+ accessWhere(service: AnyContract | string, principal: Principal, level: AccessLevel): Promise<AccessFilter>;
1441
+ /**
1442
+ * Calls `listener` after each flush whose tracked writes may have changed
1443
+ * someone's access to a row (`AccessChange`), once the cache no longer
1444
+ * holds what they changed. A promise it returns is awaited before the
1445
+ * dispatcher's other flush sinks run. Returns a function that removes it.
1446
+ */
1447
+ onAccessChanged(listener: AccessChangeListener): () => void;
1448
+ }
1449
+ /**
1450
+ * `ctx.access` (RFC 0003 section 4.3): `dispatcher.access` bound to the
1451
+ * call's caller, `ctx.principal`, with the grants that call runs with (its
1452
+ * socket's, or those `qd.caller` loaded). For a `custom(...)` form or a
1453
+ * handler that asks about a row its method's own form does not name: a
1454
+ * payment's loan, a parent named by an optional key. `service` is a
1455
+ * contract or a service name with an access policy on the dispatcher;
1456
+ * another is a `TypeError`. An anonymous caller (a `"public"` method called
1457
+ * without credentials) has no level on any row.
1458
+ *
1459
+ * @example
1460
+ * access: custom(async (ctx, input) => await ctx.access.can(loan, input.loanId, "Moderate")),
1461
+ */
1462
+ interface ContextAccess {
1463
+ /**
1464
+ * The caller's level on each of `ids` of `service`, as an `{ entry }`
1465
+ * check counts it (`dispatcher.access.levelsFor` with `ctx.principal`): a
1466
+ * service-wide `Admin` grant gives `Admin` on every id while the service
1467
+ * keeps `adminBypass` on, and a row that is not found has no level. One
1468
+ * batched lookup per policy. An empty map for an anonymous caller.
1469
+ */
1470
+ levelsFor(service: AnyContract | string, ids: readonly string[]): Promise<RowLevels>;
1471
+ /**
1472
+ * Whether the caller's level on row `id` of `service` is at least `level`,
1473
+ * as `{ entry: level }` decides it on that row: `false` for a row that is
1474
+ * not found (but for a service-wide `Admin` grant, which reaches every id
1475
+ * without reading it, as for `{ entry }`) and for an anonymous caller.
1476
+ */
1477
+ can(service: AnyContract | string, id: string, level: AccessLevel): Promise<boolean>;
1478
+ /**
1479
+ * A filter for `db.<model>.findMany({ where })` matching exactly the rows
1480
+ * of `service` on which `can` gives the caller `level`, for a hand-written
1481
+ * list (`dispatcher.access.accessWhere` with `ctx.principal`): `{}` for a
1482
+ * service-wide `Admin` with `adminBypass`, `"none"` when no row matches
1483
+ * and for an anonymous caller.
1484
+ */
1485
+ where(service: AnyContract | string, level: AccessLevel): Promise<AccessFilter>;
1486
+ }
1487
+
1320
1488
  /** Options of one in-process call. */
1321
1489
  interface CallOptions {
1322
1490
  /** Cancels the call (queries only), like a client's `qd:cancel`. */
@@ -1343,4 +1511,4 @@ type CallerFor<T extends QuickdrawTypes> = T extends {
1343
1511
  readonly contracts: infer Contracts extends ContractMap;
1344
1512
  } ? Caller<Contracts[keyof Contracts]> : Caller<AnyContract>;
1345
1513
 
1346
- export { type ProjectedOutput as $, type AnyService as A, type PublicAccess as B, type CountArgs as C, DevWarningError as D, type HandlerArgs as E, type FindManyArgs as F, type CustomAccess as G, type HandlerContext as H, type ShareMode as I, type ChannelOptions as J, type StreamOptions as K, type ChannelsRequired as L, type ModelName as M, type BaseContext as N, type CallerFor as O, type Presence as P, type AccessPolicy as Q, type RowLevels as R, type StorageAdapter as S, type AnyAccessPolicy as T, type UnitOfWorkFactory as U, type PolicyColumns as V, type WriteRecord as W, type PolicyForeign as X, type PolicyTools as Y, type RowAccess as Z, type AffectsLink as _, type StorageRow as a, type Projection as a0, type TierGroup as a1, type Tiers as a2, DEFAULT_BULK_THRESHOLD as a3, type CollectionScope as a4, type ServiceCollection as a5, type ContextRooms as a6, type ContextServices as a7, type TouchOptions as a8, type ChannelAccess as a9, type AccessForm as aA, type AccessRequest as aB, type AuthenticatedAccess as aC, type EntryAccess as aD, type IdKeyOf as aE, type IdSelector as aF, type ScopeAccess as aG, type ServiceAccess as aH, ANY_FIELD as aI, type UnitOfWork as aJ, type UnitOfWorkScope as aK, type LinkInterest as aL, formatDevWarning as aM, N_PLUS_ONE_STATEMENTS as aN, type ChannelContext as aa, type ChannelHandler as ab, type ChannelImplementation as ac, type ChannelRoomOf as ad, type RoomLeave as ae, type RoomLeaveReason as af, type RoomLeft as ag, type RoomTarget as ah, type ServiceChannel as ai, type ServiceStream as aj, type StreamImplementation as ak, type StreamPushArgs as al, type StreamPushManyArgs as am, type StreamSeed as an, type StreamSeedContext as ao, type StreamValidation as ap, type CallOptions as aq, type MethodCaller as ar, type ServiceCaller as as, type ForeignColumns as at, type ForeignColumnsOf as au, type MembershipRead as av, type ParentLink as aw, type PolicyKind as ax, type PolicyReads as ay, type RowLevel as az, type StorageWhere as b, type StatementCount as c, type Caller as d, type FlushSink as e, type FlushInfo as f, type ServiceMethod as g, type Service as h, type DevWarning as i, type DevWarningKind as j, type AccessFilter as k, type RunContext as l, type RunOptions as m, type ServerRooms as n, type StreamHandle as o, type AnyContext as p, type AccessEngine as q, type AppRooms as r, storageOf as s, type StreamSubscriptions as t, type RoomLeaveHandler as u, type PolicyFor as v, type RowForms as w, type AccessFor as x, type ModelColumn as y, type WatchAccess as z };
1514
+ export { type AffectsLink as $, type AnyService as A, type PublicAccess as B, type CountArgs as C, DevWarningError as D, type HandlerArgs as E, type FindManyArgs as F, type CustomAccess as G, type HostLeaveHandler as H, type ShareMode as I, type ChannelOptions as J, type StreamOptions as K, type ChannelsRequired as L, type ModelName as M, type BaseContext as N, type CallerFor as O, type Presence as P, type AccessPolicy as Q, type RunContext as R, type StorageAdapter as S, type AnyAccessPolicy as T, type UnitOfWorkFactory as U, type PolicyColumns as V, type WriteRecord as W, type PolicyForeign as X, type PolicyTools as Y, type AccessFilter as Z, type RowAccess as _, type StorageRow as a, type ProjectedOutput as a0, type Projection as a1, type TierGroup as a2, type Tiers as a3, DEFAULT_BULK_THRESHOLD as a4, type CollectionScope as a5, type ServiceCollection as a6, type ContextAccess as a7, type ContextRooms as a8, type ContextServices as a9, type ParentLink as aA, type PolicyKind as aB, type PolicyReads as aC, type RowLevel as aD, type RowLevels as aE, type AccessChange as aF, type AccessChangeListener as aG, type AccessForm as aH, type AccessRequest as aI, type AuthenticatedAccess as aJ, type EntryAccess as aK, type IdKeyOf as aL, type IdSelector as aM, type ScopeAccess as aN, type ServiceAccess as aO, ANY_FIELD as aP, type UnitOfWork as aQ, type UnitOfWorkScope as aR, type LinkInterest as aS, formatDevWarning as aT, N_PLUS_ONE_STATEMENTS as aU, type TouchOptions as aa, type ChannelAccess as ab, type ChannelContext as ac, type ChannelHandler as ad, type ChannelImplementation as ae, type ChannelRoomOf as af, type HostLeave as ag, type RoomLeave as ah, type RoomLeaveReason as ai, type RoomLeft as aj, type RoomTarget as ak, type ServiceChannel as al, type ServiceStream as am, type StreamImplementation as an, type StreamPushArgs as ao, type StreamPushManyArgs as ap, type StreamSeed as aq, type StreamSeedContext as ar, type StreamSubscribersArgs as as, type StreamValidation as at, type CallOptions as au, type MethodCaller as av, type ServiceCaller as aw, type ForeignColumns as ax, type ForeignColumnsOf as ay, type MembershipRead as az, type StorageWhere as b, type StatementCount as c, type Caller as d, type FlushSink as e, type FlushInfo as f, type ServiceMethod as g, type Service as h, type DevWarning as i, type DevWarningKind as j, type RunOptions as k, type DispatcherAccess as l, type ServerRooms as m, type StreamHandle as n, type AnyContext as o, type AccessEngine as p, type AppRooms as q, type StreamSubscriptions as r, storageOf as s, type RoomLeaveHandler as t, type PolicyFor as u, type RowForms as v, type AccessFor as w, type HandlerContext as x, type ModelColumn as y, type WatchAccess as z };
@@ -0,0 +1,82 @@
1
+ import {
2
+ MAX_PEER_CANDIDATE_LENGTH,
3
+ MAX_PEER_SIGNAL_LENGTH,
4
+ MAX_SCOPE_LENGTH
5
+ } from "./chunk-X4ZU4QH5.js";
6
+ import {
7
+ isRecord
8
+ } from "./chunk-QSU47XEX.js";
9
+
10
+ // src/protocol/peer.ts
11
+ var MAX_SOCKET_ID_LENGTH = 64;
12
+ function isText(value) {
13
+ return typeof value === "string" && value.length <= MAX_PEER_SIGNAL_LENGTH;
14
+ }
15
+ function isCandidateText(value) {
16
+ return typeof value === "string" && value.length <= MAX_PEER_CANDIDATE_LENGTH;
17
+ }
18
+ function isRoomName(value) {
19
+ return typeof value === "string" && value !== "" && value.length <= MAX_SCOPE_LENGTH;
20
+ }
21
+ function isSocketId(value) {
22
+ return typeof value === "string" && value !== "" && value.length <= MAX_SOCKET_ID_LENGTH;
23
+ }
24
+ function isPeerLabel(value) {
25
+ return value === "rel" || value === "fast";
26
+ }
27
+ function nullable(value, check) {
28
+ return value === void 0 || value === null || check(value);
29
+ }
30
+ function isLineIndex(value) {
31
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
32
+ }
33
+ function readDescription(value) {
34
+ if (!isRecord(value) || value.type !== "offer" && value.type !== "answer") {
35
+ return void 0;
36
+ }
37
+ return isText(value.sdp) ? { type: value.type, sdp: value.sdp } : void 0;
38
+ }
39
+ function readCandidate(value) {
40
+ if (!isRecord(value) || !isCandidateText(value.candidate)) {
41
+ return void 0;
42
+ }
43
+ const { sdpMid, sdpMLineIndex, usernameFragment } = value;
44
+ if (!nullable(sdpMid, isCandidateText) || !nullable(sdpMLineIndex, isLineIndex) || !nullable(usernameFragment, isCandidateText)) {
45
+ return void 0;
46
+ }
47
+ return {
48
+ candidate: value.candidate,
49
+ ...sdpMid === void 0 ? {} : { sdpMid },
50
+ ...sdpMLineIndex === void 0 ? {} : { sdpMLineIndex },
51
+ ...usernameFragment === void 0 ? {} : { usernameFragment }
52
+ };
53
+ }
54
+ function readSignal(value) {
55
+ if (!isRecord(value)) {
56
+ return void 0;
57
+ }
58
+ const { sdp, ice, relay, bye } = value;
59
+ if ([sdp, ice, relay, bye].filter((member) => member !== void 0).length !== 1) {
60
+ return void 0;
61
+ }
62
+ if (sdp !== void 0) {
63
+ const description = readDescription(sdp);
64
+ return description === void 0 ? void 0 : { sdp: description };
65
+ }
66
+ if (ice !== void 0) {
67
+ const candidate = readCandidate(ice);
68
+ return candidate === void 0 ? void 0 : { ice: candidate };
69
+ }
70
+ if (relay === true) {
71
+ return { relay: true };
72
+ }
73
+ return bye === true ? { bye: true } : void 0;
74
+ }
75
+
76
+ export {
77
+ isRoomName,
78
+ isSocketId,
79
+ isPeerLabel,
80
+ readSignal
81
+ };
82
+ //# sourceMappingURL=chunk-2FDSKLBO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/protocol/peer.ts"],"sourcesContent":["// Reading peer link signals (RFC 0003 section 12.5), for the server that\n// forwards them and the client that applies them. A signal is copied member\n// by member, so what goes on is only what was read: a session description\n// of at most `MAX_PEER_SIGNAL_LENGTH` characters, an ICE candidate whose\n// strings hold at most `MAX_PEER_CANDIDATE_LENGTH`, `relay` or `bye`.\n// Internal: neither the package root nor `./client` exports these.\n\nimport type { PeerCandidate, PeerDescription, PeerLabel, PeerSignal } from \"./envelope\";\nimport { isRecord } from \"./guards\";\nimport { MAX_PEER_CANDIDATE_LENGTH, MAX_PEER_SIGNAL_LENGTH, MAX_SCOPE_LENGTH } from \"./version\";\n\n/** The longest socket id a peer frame may name. Socket.IO's are 20 characters. */\nexport const MAX_SOCKET_ID_LENGTH = 64;\n\n/** True for a string of at most `MAX_PEER_SIGNAL_LENGTH` characters, empty included. */\nfunction isText(value: unknown): value is string {\n return typeof value === \"string\" && value.length <= MAX_PEER_SIGNAL_LENGTH;\n}\n\n/** True for a string of at most `MAX_PEER_CANDIDATE_LENGTH` characters, empty included. */\nfunction isCandidateText(value: unknown): value is string {\n return typeof value === \"string\" && value.length <= MAX_PEER_CANDIDATE_LENGTH;\n}\n\n/** True for what may name an app room: 1 to `MAX_SCOPE_LENGTH` characters. */\nexport function isRoomName(value: unknown): value is string {\n return typeof value === \"string\" && value !== \"\" && value.length <= MAX_SCOPE_LENGTH;\n}\n\n/** True for what may name a socket: 1 to `MAX_SOCKET_ID_LENGTH` characters. */\nexport function isSocketId(value: unknown): value is string {\n return typeof value === \"string\" && value !== \"\" && value.length <= MAX_SOCKET_ID_LENGTH;\n}\n\n/** True for `rel` and `fast`. */\nexport function isPeerLabel(value: unknown): value is PeerLabel {\n return value === \"rel\" || value === \"fast\";\n}\n\n/** True when `value` is absent, `null`, or passes `check`. */\nfunction nullable(value: unknown, check: (inner: unknown) => boolean): boolean {\n return value === undefined || value === null || check(value);\n}\n\nfunction isLineIndex(value: unknown): boolean {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\n\nfunction readDescription(value: unknown): PeerDescription | undefined {\n if (!isRecord(value) || (value.type !== \"offer\" && value.type !== \"answer\")) {\n return undefined;\n }\n return isText(value.sdp) ? { type: value.type, sdp: value.sdp } : undefined;\n}\n\nfunction readCandidate(value: unknown): PeerCandidate | undefined {\n if (!isRecord(value) || !isCandidateText(value.candidate)) {\n return undefined;\n }\n const { sdpMid, sdpMLineIndex, usernameFragment } = value;\n if (\n !nullable(sdpMid, isCandidateText) ||\n !nullable(sdpMLineIndex, isLineIndex) ||\n !nullable(usernameFragment, isCandidateText)\n ) {\n return undefined;\n }\n return {\n candidate: value.candidate,\n ...(sdpMid === undefined ? {} : { sdpMid: sdpMid as string | null }),\n ...(sdpMLineIndex === undefined ? {} : { sdpMLineIndex: sdpMLineIndex as number | null }),\n ...(usernameFragment === undefined\n ? {}\n : { usernameFragment: usernameFragment as string | null }),\n };\n}\n\n/**\n * The signal `value` holds, copied, or `undefined` unless it holds exactly\n * one of `sdp`, `ice`, `relay: true` and `bye: true`, well formed. Fields\n * it does not know are left behind.\n */\nexport function readSignal(value: unknown): PeerSignal | undefined {\n if (!isRecord(value)) {\n return undefined;\n }\n const { sdp, ice, relay, bye } = value;\n if ([sdp, ice, relay, bye].filter((member) => member !== undefined).length !== 1) {\n return undefined;\n }\n if (sdp !== undefined) {\n const description = readDescription(sdp);\n return description === undefined ? undefined : { sdp: description };\n }\n if (ice !== undefined) {\n const candidate = readCandidate(ice);\n return candidate === undefined ? undefined : { ice: candidate };\n }\n if (relay === true) {\n return { relay: true };\n }\n return bye === true ? { bye: true } : undefined;\n}\n"],"mappings":";;;;;;;;;;AAYO,IAAM,uBAAuB;AAGpC,SAAS,OAAO,OAAiC;AAC/C,SAAO,OAAO,UAAU,YAAY,MAAM,UAAU;AACtD;AAGA,SAAS,gBAAgB,OAAiC;AACxD,SAAO,OAAO,UAAU,YAAY,MAAM,UAAU;AACtD;AAGO,SAAS,WAAW,OAAiC;AAC1D,SAAO,OAAO,UAAU,YAAY,UAAU,MAAM,MAAM,UAAU;AACtE;AAGO,SAAS,WAAW,OAAiC;AAC1D,SAAO,OAAO,UAAU,YAAY,UAAU,MAAM,MAAM,UAAU;AACtE;AAGO,SAAS,YAAY,OAAoC;AAC9D,SAAO,UAAU,SAAS,UAAU;AACtC;AAGA,SAAS,SAAS,OAAgB,OAA6C;AAC7E,SAAO,UAAU,UAAa,UAAU,QAAQ,MAAM,KAAK;AAC7D;AAEA,SAAS,YAAY,OAAyB;AAC5C,SAAO,OAAO,UAAU,YAAY,OAAO,cAAc,KAAK,KAAK,SAAS;AAC9E;AAEA,SAAS,gBAAgB,OAA6C;AACpE,MAAI,CAAC,SAAS,KAAK,KAAM,MAAM,SAAS,WAAW,MAAM,SAAS,UAAW;AAC3E,WAAO;AAAA,EACT;AACA,SAAO,OAAO,MAAM,GAAG,IAAI,EAAE,MAAM,MAAM,MAAM,KAAK,MAAM,IAAI,IAAI;AACpE;AAEA,SAAS,cAAc,OAA2C;AAChE,MAAI,CAAC,SAAS,KAAK,KAAK,CAAC,gBAAgB,MAAM,SAAS,GAAG;AACzD,WAAO;AAAA,EACT;AACA,QAAM,EAAE,QAAQ,eAAe,iBAAiB,IAAI;AACpD,MACE,CAAC,SAAS,QAAQ,eAAe,KACjC,CAAC,SAAS,eAAe,WAAW,KACpC,CAAC,SAAS,kBAAkB,eAAe,GAC3C;AACA,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,WAAW,MAAM;AAAA,IACjB,GAAI,WAAW,SAAY,CAAC,IAAI,EAAE,OAAgC;AAAA,IAClE,GAAI,kBAAkB,SAAY,CAAC,IAAI,EAAE,cAA8C;AAAA,IACvF,GAAI,qBAAqB,SACrB,CAAC,IACD,EAAE,iBAAoD;AAAA,EAC5D;AACF;AAOO,SAAS,WAAW,OAAwC;AACjE,MAAI,CAAC,SAAS,KAAK,GAAG;AACpB,WAAO;AAAA,EACT;AACA,QAAM,EAAE,KAAK,KAAK,OAAO,IAAI,IAAI;AACjC,MAAI,CAAC,KAAK,KAAK,OAAO,GAAG,EAAE,OAAO,CAAC,WAAW,WAAW,MAAS,EAAE,WAAW,GAAG;AAChF,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,QAAW;AACrB,UAAM,cAAc,gBAAgB,GAAG;AACvC,WAAO,gBAAgB,SAAY,SAAY,EAAE,KAAK,YAAY;AAAA,EACpE;AACA,MAAI,QAAQ,QAAW;AACrB,UAAM,YAAY,cAAc,GAAG;AACnC,WAAO,cAAc,SAAY,SAAY,EAAE,KAAK,UAAU;AAAA,EAChE;AACA,MAAI,UAAU,MAAM;AAClB,WAAO,EAAE,OAAO,KAAK;AAAA,EACvB;AACA,SAAO,QAAQ,OAAO,EAAE,KAAK,KAAK,IAAI;AACxC;","names":[]}