@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,4 +1,4 @@
1
- import { A as AccessLevel } from './infer-BmoZsL9a.js';
1
+ import { A as AccessLevel } from './infer-Br62cnyW.js';
2
2
  import { W as WireError } from './errors-S-bxEIBC.js';
3
3
 
4
4
  /**
@@ -58,6 +58,10 @@ declare const CLIENT_EVENTS: Readonly<{
58
58
  readonly streamUnsub: "qd:stream:unsub";
59
59
  /** A fire-and-forget channel message, sent volatile: `[s, channel, payload]`. */
60
60
  readonly channel: "qd:ch";
61
+ /** A peer link's signal to another socket of an app room: `{ room, to, sig }`. */
62
+ readonly peer: "qd:peer";
63
+ /** A peer link's message for the server to relay: `[room, to, label, text]`, dropped on `fast` when backed up. */
64
+ readonly relay: "qd:relay";
61
65
  }>;
62
66
  /** Events the server sends to a client (RFC 0003 section 8.3). */
63
67
  declare const SERVER_EVENTS: Readonly<{
@@ -81,6 +85,12 @@ declare const SERVER_EVENTS: Readonly<{
81
85
  readonly rotate: "qd:rotate";
82
86
  /** The user's service grants changed. */
83
87
  readonly access: "qd:access";
88
+ /** A peer link's signal from another socket of an app room: `{ room, from, userId, sig }`. */
89
+ readonly peer: "qd:peer";
90
+ /** A peer link's message the server relays: `[room, from, label, text]`. */
91
+ readonly relay: "qd:relay";
92
+ /** An app room's host (host mode): `[room, host]`, the host's socket id or `null`. */
93
+ readonly host: "qd:host";
84
94
  }>;
85
95
  /** The name of an event a client sends. */
86
96
  type ClientEventName = (typeof CLIENT_EVENTS)[keyof typeof CLIENT_EVENTS];
@@ -122,16 +132,31 @@ interface ProtocolMismatch {
122
132
  /** True when a `connect_error`'s `data` says the server speaks another protocol. */
123
133
  declare function isProtocolMismatch(value: unknown): value is ProtocolMismatch;
124
134
  /**
125
- * The `data` of the error a server refuses a connection with when
126
- * authenticating it failed: the app's `authenticate` threw, so the
127
- * credentials are bad or could not be checked. A client tells it apart from
128
- * {@link ProtocolMismatch} by `code`; reconnecting needs other credentials.
135
+ * The `data` of the error a server refuses a connection with when it refused
136
+ * the credentials: the app's `authenticate` threw a `QuickdrawError` with
137
+ * code `UNAUTHENTICATED` (or `FORBIDDEN`), or the session it recorded
138
+ * expired during the handshake. A client tells it apart from
139
+ * {@link ProtocolMismatch} by `code`; reconnecting needs other credentials,
140
+ * so the user is signed out. A server that could not check the credentials
141
+ * refuses with {@link AuthenticationUnavailable} instead.
129
142
  */
130
143
  interface AuthenticationRefused {
131
144
  readonly code: "UNAUTHENTICATED";
132
145
  }
133
- /** True when a `connect_error`'s `data` says authenticating the connection failed. */
146
+ /** True when a `connect_error`'s `data` says the server refused the connection's credentials. */
134
147
  declare function isAuthenticationRefused(value: unknown): value is AuthenticationRefused;
148
+ /**
149
+ * The `data` of the error a server refuses a connection with when it could
150
+ * not authenticate it: the app's `authenticate` (or `loadServiceAccess`)
151
+ * failed with anything but a refusal, its session store or database down,
152
+ * say. The credentials may well be good, so a client keeps the user it had
153
+ * and connects again later, backing off as after a lost connection.
154
+ */
155
+ interface AuthenticationUnavailable {
156
+ readonly code: "INTERNAL";
157
+ }
158
+ /** True when a `connect_error`'s `data` says the server could not authenticate the connection. */
159
+ declare function isAuthenticationUnavailable(value: unknown): value is AuthenticationUnavailable;
135
160
  /** The most rows one socket may hold entity subscriptions to at once, as `qd:hello` announces it. */
136
161
  declare const MAX_ENTITY_IDS_PER_SOCKET = 10000;
137
162
  /** The most collection scopes one socket may hold at once, as `qd:hello` announces it. */
@@ -155,6 +180,25 @@ interface HelloSubscriptionLimits {
155
180
  /** Change topics one socket may watch at once; one more is `CONFLICT`. Absent from servers up to 5.1.0, which have no such cap. */
156
181
  readonly maxTopics?: number;
157
182
  }
183
+ /**
184
+ * What one socket may signal and relay over peer links (RFC 0003 section
185
+ * 12.5), as `qd:hello` announces it. A client keeps its relay messages
186
+ * within these, so a `rel` message is never dropped for its rate.
187
+ */
188
+ interface HelloPeerLimits {
189
+ /** Peers one socket may signal at once; a signal to one more is `CONFLICT`. */
190
+ readonly maxLinks: number;
191
+ /** The longest link message, in UTF-8 bytes, on the data channel and through the relay alike. */
192
+ readonly maxMessageBytes: number;
193
+ /** Relay messages one socket may send to one peer per second; more are dropped. */
194
+ readonly relayRate: number;
195
+ /** Relay messages one socket may send to one peer at once, after a pause. */
196
+ readonly relayBurst: number;
197
+ /** Relay bytes one socket may send per second, to all its peers together; more are dropped. */
198
+ readonly relayBytesPerSecond: number;
199
+ /** Relay bytes one socket may send at once, after a pause. */
200
+ readonly relayBytesBurst: number;
201
+ }
158
202
  /** The limits a server announces in `qd:hello`, so a client can stay inside them. */
159
203
  interface HelloLimits {
160
204
  /** Queries one socket may have running at once; more wait in a queue (RFC 0003 section 9). */
@@ -171,6 +215,8 @@ interface HelloLimits {
171
215
  readonly callTimeoutMs: number;
172
216
  /** The socket's lane of subscription events. */
173
217
  readonly subscriptions: HelloSubscriptionLimits;
218
+ /** What peer links may signal and relay. Absent from a server that serves no peer links, whose `features` lacks `"peer"`. */
219
+ readonly peers?: HelloPeerLimits;
174
220
  }
175
221
  /**
176
222
  * `qd:hello`: the server's answer to a v5 handshake, sent once per
@@ -191,7 +237,12 @@ interface HelloFrame {
191
237
  readonly serverId: string;
192
238
  /** What a client must stay within. */
193
239
  readonly limits: HelloLimits;
194
- /** Names of optional server features that are on. Informational only. */
240
+ /**
241
+ * Names of optional server features that are on: `"binary"` (the stock
242
+ * parser, `createServer({ binary: true })`) and `"peer"` (peer links,
243
+ * `createServer({ peers: true })`). Informational: a client that finds no
244
+ * `"peer"` opens no peer link.
245
+ */
195
246
  readonly features: readonly string[];
196
247
  /** The user the socket acts for, or `null` when it is anonymous. */
197
248
  readonly userId: string | null;
@@ -513,6 +564,142 @@ interface PresenceFrame {
513
564
  /** A user who left the room: their last socket in it left or disconnected. */
514
565
  readonly left?: string;
515
566
  }
567
+ /**
568
+ * A peer link's two channels: `rel`, ordered and reliable, and `fast`,
569
+ * unordered and never retransmitted (dropped where a connection is backed up).
570
+ */
571
+ type PeerLabel = "rel" | "fast";
572
+ /** A WebRTC session description, as `RTCSessionDescription.toJSON()` writes it. */
573
+ interface PeerDescription {
574
+ readonly type: "offer" | "answer";
575
+ readonly sdp: string;
576
+ }
577
+ /** A WebRTC ICE candidate, as `RTCIceCandidate.toJSON()` writes it. */
578
+ interface PeerCandidate {
579
+ readonly candidate: string;
580
+ readonly sdpMid?: string | null;
581
+ readonly sdpMLineIndex?: number | null;
582
+ readonly usernameFragment?: string | null;
583
+ }
584
+ /**
585
+ * What one `qd:peer` frame says about a link, in exactly one member: the
586
+ * offerer's `offer` or the answerer's `answer` (`sdp`), one ICE candidate
587
+ * (`ice`), that the sender sends the link's messages through the relay
588
+ * from now on (`relay`), or that the link is over (`bye`): the sender
589
+ * closed it or, when the server sends it, left the room or disconnected.
590
+ */
591
+ interface PeerSignal {
592
+ readonly sdp?: PeerDescription;
593
+ readonly ice?: PeerCandidate;
594
+ readonly relay?: true;
595
+ readonly bye?: true;
596
+ }
597
+ /**
598
+ * `qd:peer`, from a client: a signal for socket `to` (another socket's id)
599
+ * about the link the two have in app room `room`, which both must be in.
600
+ * Acknowledged when asked: `Ok`, or `UNAUTHENTICATED`, `FORBIDDEN` (the
601
+ * sender is not in the room), `NOT_FOUND` (no signed-in socket `to` is in
602
+ * the room; behind a cluster adapter a socket on another node is not
603
+ * checked before the signal goes), `CONFLICT` (the sender already signals
604
+ * `limits.peers.maxLinks` peers), `RATE_LIMITED` or `VALIDATION`.
605
+ */
606
+ interface PeerSignalFrame {
607
+ readonly room: string;
608
+ readonly to: string;
609
+ readonly sig: PeerSignal;
610
+ }
611
+ /**
612
+ * `qd:peer`, from the server: a signal from socket `from` about the link in
613
+ * app room `room`. `userId` is the sender's user, as the server knows it.
614
+ */
615
+ interface PeerForwardFrame {
616
+ readonly room: string;
617
+ readonly from: string;
618
+ readonly userId: string;
619
+ readonly sig: PeerSignal;
620
+ }
621
+ /**
622
+ * `qd:relay`, from a client, never acknowledged: a link message for socket
623
+ * `to` in app room `room`. `text` is a `PeerMessage` as JSON, at most
624
+ * `limits.peers.maxMessageBytes`. The two sockets must have signalled each
625
+ * other in that room; a message over the rate or the byte budget of
626
+ * `limits.peers`, or to a socket that left the room, is dropped, and so is
627
+ * one on `fast` while the receiving socket's connection is backed up
628
+ * (`PEER_RELAY_FAST_BACKLOG`). A later revision may append elements after
629
+ * `text`.
630
+ */
631
+ type RelayFrame = readonly [room: string, to: string, label: PeerLabel, text: string];
632
+ /** `qd:relay`, from the server: a link message from socket `from` in app room `room`. */
633
+ type RelayForwardFrame = readonly [
634
+ room: string,
635
+ from: string,
636
+ label: PeerLabel,
637
+ text: string
638
+ ];
639
+ /**
640
+ * A peer link message: the JSON text of one data channel message or of a
641
+ * relayed `text`, alike on both paths. A receiver ignores a message whose
642
+ * first element it does not know, and elements after the ones it reads.
643
+ */
644
+ type PeerMessage = PeerData | PeerPing | PeerPong | HostMessage;
645
+ /** A link message carrying the app's `data`, any JSON value. */
646
+ type PeerData = readonly [kind: 0, data: unknown];
647
+ /** A clock ping: `t` is the sender's clock in milliseconds. Sent on `fast`. */
648
+ type PeerPing = readonly [kind: 1, t: number];
649
+ /** The pong of a ping: `t` as the ping carried it, `u` the answerer's clock as it answered. Sent on `fast`. */
650
+ type PeerPong = readonly [kind: 2, t: number, u: number];
651
+ /**
652
+ * A host mode message (section 12.5): what a peer and its room's host send
653
+ * each other over their link, kept apart from the app's own messages.
654
+ */
655
+ type HostMessage = HostChannelMessage | HostSubscribe | HostUnsubscribe | HostSeed | HostItem | HostRefusal;
656
+ /** A message on a host-served channel, from a peer to the host of the channel's room. Sent on `fast`. */
657
+ type HostChannelMessage = readonly [
658
+ kind: 3,
659
+ service: string,
660
+ channel: string,
661
+ payload: unknown
662
+ ];
663
+ /** Subscribes to a feed of a host-served stream, from a peer to the host of its room. Sent on `rel`. */
664
+ type HostSubscribe = readonly [kind: 4, service: string, stream: string, scope: string];
665
+ /** Leaves a feed of a host-served stream. Sent on `rel`. */
666
+ type HostUnsubscribe = readonly [kind: 5, service: string, stream: string, scope: string];
667
+ /**
668
+ * The seed of a feed a peer subscribed to, from the host: the latest items
669
+ * it kept (or computed), oldest first, in chunks that each fit the message
670
+ * limit; `last` is true on the last chunk. Sent on `rel`.
671
+ */
672
+ type HostSeed = readonly [
673
+ kind: 6,
674
+ service: string,
675
+ stream: string,
676
+ scope: string,
677
+ items: readonly unknown[],
678
+ last: boolean
679
+ ];
680
+ /** An item pushed to a feed, from the host: on `fast` for a volatile stream, else on `rel`. */
681
+ type HostItem = readonly [
682
+ kind: 7,
683
+ service: string,
684
+ stream: string,
685
+ scope: string,
686
+ item: unknown
687
+ ];
688
+ /** A subscribe the host refused (`NOT_FOUND`, `FORBIDDEN`, ...), from the host. Sent on `rel`. */
689
+ type HostRefusal = readonly [
690
+ kind: 8,
691
+ service: string,
692
+ stream: string,
693
+ scope: string,
694
+ error: WireError
695
+ ];
696
+ /**
697
+ * `qd:host`, from the server: the host of app room `room` (the socket that
698
+ * serves its host-served channels and streams), or `null` when it has none.
699
+ * Sent to the room's sockets on every change, and to a socket that joins a
700
+ * room with a host.
701
+ */
702
+ type HostFrame = readonly [room: string, host: string | null];
516
703
  /** Why the server ended a subscription. */
517
704
  type RevokeReason = "access" | "anchor-deleted";
518
705
  /**
@@ -564,6 +751,8 @@ interface ClientListeners {
564
751
  streamSub: (frame: StreamSubscribe, ack: Ack<StreamSubscribeReply>) => void;
565
752
  streamUnsub: (frame: StreamSubscribe, ack?: Ack<Ok | Failure>) => void;
566
753
  channel: (frame: ChannelFrame) => void;
754
+ peer: (frame: PeerSignalFrame, ack?: Ack<Ok | Failure>) => void;
755
+ relay: (frame: RelayFrame) => void;
567
756
  }
568
757
  /** The listener of each server event, by its key in `SERVER_EVENTS`. */
569
758
  interface ServerListeners {
@@ -577,6 +766,9 @@ interface ServerListeners {
577
766
  presence: (frame: PresenceFrame) => void;
578
767
  rotate: (frame: RotateFrame) => void;
579
768
  access: (frame: AccessFrame) => void;
769
+ peer: (frame: PeerForwardFrame) => void;
770
+ relay: (frame: RelayForwardFrame) => void;
771
+ host: (frame: HostFrame) => void;
580
772
  }
581
773
  /**
582
774
  * The events a v5 client sends, keyed by name (`"qd:call"`, ...). The server
@@ -601,4 +793,4 @@ declare function isCallEnvelope(value: unknown): value is CallEnvelope;
601
793
  /** True when `value` has the shape of a `qd:cancel` frame. Unknown keys are ignored. */
602
794
  declare function isCancel(value: unknown): value is CancelFrame;
603
795
 
604
- export { type EntityUnsubscribe as $, type AuthenticationRefused as A, type ChangedFrame as B, CLIENT_EVENTS as C, type ChannelFrame as D, type ClientToServerEvents as E, type CollectionDelta as F, type CollectionFrame as G, type HandshakeAuth as H, type CollectionItemsReply as I, type CollectionItemsRequest as J, type CollectionResumed as K, type CollectionScopeRef as L, type CollectionSnapshot as M, type CollectionSubscribe as N, type CollectionSubscribeReply as O, PROTOCOL_MISMATCH as P, type QdHandshake as Q, RESERVED_ROOM_PREFIXES as R, SERVER_EVENTS as S, type EntityFrame as T, type EntityNotModified as U, type EntityPatch as V, type EntityRemove as W, type EntityResult as X, type EntityRow as Y, type EntitySubscribe as Z, type EntitySubscribeReply as _, SERVICE_TOPIC as a, type EntityUpdate as a0, type EventFrame as a1, type Failure as a2, type Ok as a3, type PresenceFrame as a4, type Revision as a5, type RevokedFrame as a6, type RevokeReason as a7, type RotateFrame as a8, type ServerToClientEvents as a9, type StreamFrame as aa, type StreamSubscribe as ab, type StreamSubscribeReply as ac, type Version as ad, type WatchFrame as ae, type WireIndexRow as af, MAX_ENTITY_IDS_PER_SOCKET as ag, MAX_SCOPES_PER_SOCKET as ah, MAX_TOPICS_PER_SOCKET as ai, collectionTopic as b, collectionRoom as c, type ClientEventName as d, entityRoom as e, type ServerEventName as f, PROTOCOL_VERSION as g, isProtocolMismatch as h, isAuthenticationRefused as i, isQdHandshake as j, type HelloFrame as k, type HelloLimits as l, type HelloSubscriptionLimits as m, type ProtocolMismatch as n, isCallEnvelope as o, isCancel as p, type AccessFrame as q, type CallEnvelope as r, streamRoom as s, topicRoom as t, userRoom as u, type CallId as v, type CallNotModified as w, type CallReply as x, type CallSuccess as y, type CancelFrame as z };
796
+ export { type EntityRow as $, type AuthenticationRefused as A, type CallReply as B, CLIENT_EVENTS as C, type CallSuccess as D, type CancelFrame as E, type ChangedFrame as F, type ChannelFrame as G, type HandshakeAuth as H, type ClientToServerEvents as I, type CollectionDelta as J, type CollectionFrame as K, type CollectionItemsReply as L, type CollectionItemsRequest as M, type CollectionResumed as N, type CollectionScopeRef as O, PROTOCOL_MISMATCH as P, type QdHandshake as Q, RESERVED_ROOM_PREFIXES as R, SERVER_EVENTS as S, type CollectionSnapshot as T, type CollectionSubscribe as U, type CollectionSubscribeReply as V, type EntityFrame as W, type EntityNotModified as X, type EntityPatch as Y, type EntityRemove as Z, type EntityResult as _, SERVICE_TOPIC as a, type EntitySubscribe as a0, type EntitySubscribeReply as a1, type EntityUnsubscribe as a2, type EntityUpdate as a3, type EventFrame as a4, type Failure as a5, type Ok as a6, type PeerCandidate as a7, type PeerData as a8, type PeerDescription as a9, type Version as aA, type WatchFrame as aB, type WireIndexRow as aC, MAX_ENTITY_IDS_PER_SOCKET as aD, MAX_SCOPES_PER_SOCKET as aE, MAX_TOPICS_PER_SOCKET as aF, type PeerForwardFrame as aa, type PeerLabel as ab, type PeerMessage as ac, type PeerPing as ad, type PeerPong as ae, type PeerSignal as af, type PeerSignalFrame as ag, type PresenceFrame as ah, type RelayForwardFrame as ai, type HostChannelMessage as aj, type HostFrame as ak, type HostItem as al, type HostMessage as am, type HostRefusal as an, type HostSeed as ao, type HostSubscribe as ap, type HostUnsubscribe as aq, type RelayFrame as ar, type Revision as as, type RevokedFrame as at, type RevokeReason as au, type RotateFrame as av, type ServerToClientEvents as aw, type StreamFrame as ax, type StreamSubscribe as ay, type StreamSubscribeReply as az, collectionTopic as b, collectionRoom as c, type ClientEventName as d, entityRoom as e, type ServerEventName as f, PROTOCOL_VERSION as g, isAuthenticationUnavailable as h, isAuthenticationRefused as i, isProtocolMismatch as j, isQdHandshake as k, type AuthenticationUnavailable as l, type HelloFrame as m, type HelloLimits as n, type HelloPeerLimits as o, type HelloSubscriptionLimits as p, type ProtocolMismatch as q, isCallEnvelope as r, streamRoom as s, topicRoom as t, userRoom as u, isCancel as v, type AccessFrame as w, type CallEnvelope as x, type CallId as y, type CallNotModified as z };
@@ -1,12 +1,12 @@
1
1
  import { IncomingMessage, ServerResponse } from 'node:http';
2
2
  import { L as Logger } from './logger-Yz93KzdV.js';
3
- import { J as AnyContract, A as AccessLevel } from './infer-BmoZsL9a.js';
4
- import { P as Principal, T as Transport, a as McpContext, D as DbOf, c as PrincipalOf, M as MaybePromise } from './types-CYliTP65.js';
5
- import { A as AnyService, g as ServiceMethod, R as RowLevels, k as AccessFilter, d as Caller, l as RunContext, m as RunOptions, P as Presence, n as ServerRooms, o as StreamHandle, p as AnyContext, S as StorageAdapter, U as UnitOfWorkFactory, e as FlushSink, q as AccessEngine } from './caller-BT-Mv4bD.js';
6
- import { ad as Version, x as CallReply } from './envelope-DzWyIXjj.js';
3
+ import { J as AnyContract } from './infer-Br62cnyW.js';
4
+ import { A as AnyService, g as ServiceMethod, d as Caller, R as RunContext, k as RunOptions, l as DispatcherAccess, P as Presence, m as ServerRooms, n as StreamHandle, o as AnyContext, S as StorageAdapter, U as UnitOfWorkFactory, e as FlushSink, p as AccessEngine } from './caller-BTwGl7vm.js';
5
+ import { P as Principal, T as Transport, a as McpContext, D as DbOf, b as PrincipalOf, c as McpContextOf, M as MaybePromise } from './types-CLRCQGnO.js';
6
+ import { aA as Version, B as CallReply } from './envelope-BMBaxppV.js';
7
7
  import { Q as QuickdrawError } from './errors-S-bxEIBC.js';
8
- import { C as CallRecord } from './metrics-DW80Exve.js';
9
- import { S as ServerAuth } from './auth-DXiSJZaf.js';
8
+ import { C as CallRecord } from './metrics-CTVpw0gu.js';
9
+ import { S as ServerAuth } from './auth-DtdYjrZ9.js';
10
10
 
11
11
  /** How one call ended. The dispatcher's `call` resolves with it and never rejects. */
12
12
  type DispatchResult = {
@@ -65,7 +65,9 @@ interface DispatchRequest {
65
65
  readonly v?: Version;
66
66
  /**
67
67
  * The fields the MCP bridge's `context` option produced for this call,
68
- * which the handler reads as `ctx.mcp`. Only the MCP transport sets it.
68
+ * which the handler reads as `ctx.mcp`. The MCP transport sets it, and a
69
+ * call's `ctx.services` passes its own on to the calls it makes, whose
70
+ * transport is `"internal"`.
69
71
  */
70
72
  readonly mcp?: McpContext;
71
73
  /**
@@ -95,47 +97,6 @@ interface Registry {
95
97
  find(service: string, method: string): RegisteredMethod | undefined;
96
98
  }
97
99
 
98
- /**
99
- * A row whose access may have changed: who may now see more or less of it.
100
- * `id` is the row (the anchor subscriptions record); without it, any row of
101
- * the service. `userId` is the user whose level may have changed; without it,
102
- * anyone's.
103
- */
104
- interface AccessChange {
105
- /** The service name. */
106
- readonly service: string;
107
- readonly id?: string;
108
- readonly userId?: string;
109
- }
110
- /** Receives access changes; a promise it returns is awaited before the flush moves on. */
111
- type AccessChangeListener = (change: AccessChange) => void | PromiseLike<void>;
112
-
113
- /** The dispatcher's view of its services' access policies: `dispatcher.access`. */
114
- interface DispatcherAccess {
115
- /**
116
- * The principal's level on each of `ids` of `service`, as an `{ entry }`
117
- * check counts it: the service's policy, or `Admin` on every row when the
118
- * principal holds a service-wide `Admin` grant and the service keeps
119
- * `adminBypass` on. A grant below `Admin` does not count. A row that is
120
- * not found has no level. One batched lookup per policy.
121
- */
122
- levelsFor(service: AnyContract | string, principal: Principal, ids: readonly string[]): Promise<RowLevels>;
123
- /**
124
- * A filter for `db.<model>.findMany({ where })` matching exactly the rows of
125
- * `service` on which `levelsFor` gives the principal at least `level`:
126
- * `{}` (every row) for a service-wide `Admin` with `adminBypass`, or
127
- * `"none"` when no row matches.
128
- */
129
- accessWhere(service: AnyContract | string, principal: Principal, level: AccessLevel): Promise<AccessFilter>;
130
- /**
131
- * Calls `listener` after each flush whose tracked writes may have changed
132
- * someone's access to a row (`AccessChange`), once the cache no longer
133
- * holds what they changed. A promise it returns is awaited before the
134
- * dispatcher's other flush sinks run. Returns a function that removes it.
135
- */
136
- onAccessChanged(listener: AccessChangeListener): () => void;
137
- }
138
-
139
100
  type TypesOf<S extends readonly AnyService[]> = NonNullable<S[number]["~types"]>;
140
101
  /** The database client the services of `S` were declared with. */
141
102
  type DbOfServices<S extends readonly AnyService[]> = [S[number]] extends [never] ? unknown : DbOf<TypesOf<S>>;
@@ -143,6 +104,8 @@ type DbOfServices<S extends readonly AnyService[]> = [S[number]] extends [never]
143
104
  type PrincipalOfServices<S extends readonly AnyService[]> = [S[number]] extends [never] ? Principal : PrincipalOf<TypesOf<S>>;
144
105
  /** The contracts the services of `S` were defined from. */
145
106
  type ContractOfServices<S extends readonly AnyService[]> = [S[number]] extends [never] ? AnyContract : S[number]["contract"];
107
+ /** The type of `ctx.mcp` for the services of `S`: their app's `QuickdrawTypes["mcp"]`. */
108
+ type McpContextOfServices<S extends readonly AnyService[]> = [S[number]] extends [never] ? McpContext : McpContextOf<TypesOf<S>>;
146
109
  /**
147
110
  * The options `createDispatcher` and `createServer` share: the services and
148
111
  * the database client handlers receive, plus the pipeline's seams and
@@ -238,7 +201,9 @@ interface Dispatcher<S extends readonly AnyService[] = readonly AnyService[]> {
238
201
  /**
239
202
  * The handle of one of the services' streams (RFC 0003 section 12.5), whose
240
203
  * `push` appends an item: `dispatcher.stream(task, "logs").push(taskId,
241
- * line)`. Throws a `TypeError` for a stream the dispatcher does not serve.
204
+ * line)`, and whose `subscribers(taskId)` counts the sockets that watch the
205
+ * feed on every node. Throws a `TypeError` for a stream the dispatcher does
206
+ * not serve, a host-served one included.
242
207
  */
243
208
  stream<C extends AnyContract, K extends keyof C["streams"] & string>(contract: C, name: K): StreamHandle<C, K>;
244
209
  readonly registry: Registry;
@@ -490,4 +455,4 @@ interface HttpRouterOptions<P extends Principal = Principal> extends HttpTranspo
490
455
  */
491
456
  declare function createHttpRouter<P extends Principal = Principal>(options: HttpRouterOptions<P>): HttpRouter;
492
457
 
493
- export { type AccessOptions as A, type ContractOfServices as C, type Dispatcher as D, type HttpRouter as H, type LimitsOptions as L, type PrincipalOfServices as P, type RegisteredMethod as R, type SharedData as S, type TrackingOptions as T, type VersionRequest as V, type DispatcherBaseOptions as a, type HttpTransportOptions as b, type DispatcherOptions as c, type DispatcherCollections as d, type ChangeLogOptions as e, createDispatcher as f, type DbOfServices as g, type Registry as h, type DispatchRequest as i, type DispatchResult as j, DEFAULT_LIMITS as k, type DispatcherLimits as l, type PipelineOptions as m, type SubscriptionLimits as n, type DispatcherAccess as o, type AccessChange as p, type AccessChangeListener as q, type VersionSource as r, createHttpRouter as s, toCallReply as t, type HttpMiddleware as u, type HttpRouterOptions as v };
458
+ export { type AccessOptions as A, type ContractOfServices as C, type Dispatcher as D, type HttpRouter as H, type LimitsOptions as L, type McpContextOfServices as M, type PrincipalOfServices as P, type RegisteredMethod as R, type SharedData as S, type TrackingOptions as T, type VersionRequest as V, type DispatcherBaseOptions as a, type HttpTransportOptions as b, type DispatcherOptions as c, type DispatcherCollections as d, type ChangeLogOptions as e, createDispatcher as f, type DbOfServices as g, type Registry as h, type DispatchRequest as i, type DispatchResult as j, DEFAULT_LIMITS as k, type DispatcherLimits as l, type PipelineOptions as m, type SubscriptionLimits as n, type VersionSource as o, createHttpRouter as p, type HttpMiddleware as q, type HttpRouterOptions as r, toCallReply as t };
package/dist/index.d.ts CHANGED
@@ -1,12 +1,13 @@
1
- export { a as ACE, b as ACL, A as AccessLevel, J as AnyContract, Y as CHANNEL_DEFAULT_RATE, a0 as ChannelDef, a9 as ChannelInputOf, aa as ChannelName, ab as ChannelPayloadOf, a1 as ChannelRequires, C as CollectionDef, ac as CollectionName, ad as CollectionOf, y as CollectionWhere, K as Contract, L as ContractDefinition, ae as ContractMap, D as DEFAULT_COLLECTION_LIMIT, w as DEFAULT_COLLECTION_MAX_LIMIT, af as EntityOf, E as EntityProjection, a2 as EventDef, ag as EventName, ah as EventPayloadOf, ai as FullProjectionOf, Z as GLOBAL_STREAM, aj as IndexFieldOf, R as IndexRow, ak as IndexRowOf, I as InferInput, c as InferOutput, al as InputOf, am as IsScopedStream, an as ItemOf, ao as KindOf, M as MethodDef, k as MethodKind, ap as MethodName, aq as MethodOf, o as MethodOutput, p as MutationDef, N as NullableProjection, O as OrderBy, ar as OutputOf, as as ParsedInputOf, a3 as PayloadSelector, P as ProjectionList, at as ProjectionName, au as ProjectionOf, r as ProjectionRef, Q as QueryDef, av as ReceivedRow, U as ReservedMethodName, a4 as RoomPrefix, a5 as RoomSelector, X as RowSchema, _ as STREAM_MAX_SEED, aw as ScopeOf, s as ServiceModelsWatch, ax as ServiceNameOf, u as ServiceWatch, z as SortDirection, S as StandardJSONSchemaV1, d as StandardSchemaV1, e as StandardSchemaWithJSON, f as StandardTypedV1, a6 as StreamAccess, a7 as StreamDef, ay as StreamItemOf, az as StreamName, a8 as StreamRoom, T as TODO_SCHEMA_VENDOR, g as TodoSchemaOptions, V as ValidationIssue, j as ValidationResult, B as ViaScope, aA as ViewName, G as ViewPredicate, F as Viewer, W as Watch, H as defineContract, h as hasJsonSchema, $ as isScopedStream, i as isStandardSchema, l as listOf, m as mutation, n as nullable, q as query, t as todoSchema, v as validate, x as via } from './infer-BmoZsL9a.js';
1
+ export { a as ACE, b as ACL, A as AccessLevel, J as AnyContract, Y as CHANNEL_DEFAULT_RATE, a0 as ChannelDef, a9 as ChannelInputOf, aa as ChannelName, ab as ChannelPayloadOf, a1 as ChannelRequires, C as CollectionDef, ac as CollectionName, ad as CollectionOf, y as CollectionWhere, K as Contract, L as ContractDefinition, ae as ContractMap, D as DEFAULT_COLLECTION_LIMIT, w as DEFAULT_COLLECTION_MAX_LIMIT, af as EntityOf, E as EntityProjection, a2 as EventDef, ag as EventName, ah as EventPayloadOf, ai as FullProjectionOf, Z as GLOBAL_STREAM, aj as IndexFieldOf, R as IndexRow, ak as IndexRowOf, I as InferInput, c as InferOutput, al as InputOf, am as IsScopedStream, an as ItemOf, ao as KindOf, M as MethodDef, k as MethodKind, ap as MethodName, aq as MethodOf, o as MethodOutput, p as MutationDef, N as NullableProjection, O as OrderBy, ar as OutputOf, as as ParsedInputOf, a3 as PayloadSelector, P as ProjectionList, at as ProjectionName, au as ProjectionOf, r as ProjectionRef, Q as QueryDef, av as ReceivedRow, U as ReservedMethodName, a4 as RoomPrefix, a5 as RoomSelector, X as RowSchema, _ as STREAM_MAX_SEED, aw as ScopeOf, s as ServiceModelsWatch, ax as ServiceNameOf, u as ServiceWatch, z as SortDirection, S as StandardJSONSchemaV1, d as StandardSchemaV1, e as StandardSchemaWithJSON, f as StandardTypedV1, a6 as StreamAccess, a7 as StreamDef, ay as StreamItemOf, az as StreamName, a8 as StreamRoom, T as TODO_SCHEMA_VENDOR, g as TodoSchemaOptions, V as ValidationIssue, j as ValidationResult, B as ViaScope, aA as ViewName, G as ViewPredicate, F as Viewer, W as Watch, H as defineContract, h as hasJsonSchema, $ as isScopedStream, i as isStandardSchema, l as listOf, m as mutation, n as nullable, q as query, t as todoSchema, v as validate, x as via } from './infer-Br62cnyW.js';
2
2
  export { C as ConsoleLoggerOptions, b as LogLevel, L as Logger, c as consoleLogger, a as createConsoleLogger } from './logger-Yz93KzdV.js';
3
- export { A as ADMIN_METHODS, w as AdminContractOptions, x as AdminCreateDef, y as AdminDeleteDef, z as AdminGetDef, D as AdminListDef, E as AdminMetaDef, F as AdminMethodName, G as AdminMethods, H as AdminMethodsOf, J as AdminReemitDef, K as AdminSubscribersDef, M as AdminTag, O as AdminUpdateDef, B as BulkPatch, t as BulkResult, s as CRUD_MAX_IDS, C as CRUD_METHODS, a as CrudBulkDelete, b as CrudBulkUpdate, d as CrudContractOptions, e as CrudCreate, f as CrudDelete, g as CrudGet, h as CrudGetMany, i as CrudInputOptions, j as CrudList, k as CrudListOptions, l as CrudMethodName, m as CrudMethods, n as CrudReorder, o as CrudReorderOptions, p as CrudTag, q as CrudToggle, r as CrudUpdate, I as IdInput, u as IdsInput, P as KitSchema, L as ListInput, N as NumberFieldOf, R as ReorderInput, S as ScalarFieldOf, W as WithId, v as admin, c as crud } from './admin-DWWrT1h6.js';
4
- export { o as ADMIN_DEFAULT_PAGE_SIZE, A as ADMIN_FIELD_TYPES, p as ADMIN_MAX_PAGE, q as ADMIN_MAX_PAGE_SIZE, k as ADMIN_NEVER_WRITABLE, r as AdminCreateInput, s as AdminCreateQuery, t as AdminData, l as AdminFieldConfig, m as AdminFieldType, u as AdminListInput, v as AdminListQuery, w as AdminMetaInput, x as AdminNeverWritable, y as AdminPage, n as AdminServiceMeta, z as AdminSubscribers, B as AdminUpdateInput, C as AdminUpdateQuery, D as AdminWritable, F as FilterValue, L as LIST_DEFAULT_LIMIT, a as LIST_MAX_LIMIT, b as ListPage, c as ListQuery, d as ListSort, S as SEARCH_DEFAULT_LIMIT, e as SEARCH_DEFAULT_MIN_LENGTH, f as SEARCH_MAX_LIMIT, g as SEARCH_MAX_QUERY_LENGTH, h as SearchInput, i as SearchPage, j as SearchQuery, E as SubscriberLevel } from './adminSchemas-D4bFKsrb.js';
5
- export { A as AclMethodName, I as InviteByNameInput, z as InviteByNameQuery, B as InviteInput, C as InviteQuery, L as LeaveInput, D as ListMembersInput, E as ListMembersQuery, F as Member, G as MemberInput, M as MembersMethodName, H as MembersPage, y as SHARE_LEVELS, d as SHARING_METHODS, S as SearchContractOptions, a as SearchDef, b as SearchMethods, c as SearchTag, J as SetRoleInput, K as ShareByNameInput, N as ShareByNameQuery, O as ShareInput, P as ShareLevel, f as SharingByNameMethod, g as SharingContractOptions, h as SharingDefOf, i as SharingInvite, j as SharingInviteByName, k as SharingLeave, l as SharingListMembers, m as SharingListShares, n as SharingMethodName, o as SharingMethods, p as SharingMode, q as SharingRemove, r as SharingSetLevel, t as SharingSetRole, u as SharingShare, v as SharingShareByName, w as SharingTag, x as SharingUnshare, T as TextFieldOf, U as UnshareInput, Q as UserLookupInput, s as search, e as sharing } from './sharing-UDLn1049.js';
6
- export { q as AccessFrame, A as AuthenticationRefused, C as CLIENT_EVENTS, r as CallEnvelope, v as CallId, w as CallNotModified, x as CallReply, y as CallSuccess, z as CancelFrame, B as ChangedFrame, D as ChannelFrame, d as ClientEventName, E as ClientToServerEvents, F as CollectionDelta, G as CollectionFrame, I as CollectionItemsReply, J as CollectionItemsRequest, K as CollectionResumed, L as CollectionScopeRef, M as CollectionSnapshot, N as CollectionSubscribe, O as CollectionSubscribeReply, T as EntityFrame, U as EntityNotModified, V as EntityPatch, W as EntityRemove, X as EntityResult, Y as EntityRow, Z as EntitySubscribe, _ as EntitySubscribeReply, $ as EntityUnsubscribe, a0 as EntityUpdate, a1 as EventFrame, a2 as Failure, H as HandshakeAuth, k as HelloFrame, l as HelloLimits, m as HelloSubscriptionLimits, a3 as Ok, P as PROTOCOL_MISMATCH, g as PROTOCOL_VERSION, a4 as PresenceFrame, n as ProtocolMismatch, Q as QdHandshake, R as RESERVED_ROOM_PREFIXES, a5 as Revision, a7 as RevokeReason, a6 as RevokedFrame, a8 as RotateFrame, S as SERVER_EVENTS, a as SERVICE_TOPIC, f as ServerEventName, a9 as ServerToClientEvents, aa as StreamFrame, ab as StreamSubscribe, ac as StreamSubscribeReply, ad as Version, ae as WatchFrame, af as WireIndexRow, c as collectionRoom, b as collectionTopic, e as entityRoom, i as isAuthenticationRefused, o as isCallEnvelope, p as isCancel, h as isProtocolMismatch, j as isQdHandshake, s as streamRoom, t as topicRoom, u as userRoom } from './envelope-DzWyIXjj.js';
3
+ export { A as ADMIN_METHODS, w as AdminContractOptions, x as AdminCreateDef, y as AdminDeleteDef, z as AdminGetDef, D as AdminListDef, E as AdminMetaDef, F as AdminMethodName, G as AdminMethods, H as AdminMethodsOf, J as AdminReemitDef, K as AdminSubscribersDef, M as AdminTag, O as AdminUpdateDef, B as BulkPatch, t as BulkResult, s as CRUD_MAX_IDS, C as CRUD_METHODS, a as CrudBulkDelete, b as CrudBulkUpdate, d as CrudContractOptions, e as CrudCreate, f as CrudDelete, g as CrudGet, h as CrudGetMany, i as CrudInputOptions, j as CrudList, k as CrudListOptions, l as CrudMethodName, m as CrudMethods, n as CrudReorder, o as CrudReorderOptions, p as CrudTag, q as CrudToggle, r as CrudUpdate, I as IdInput, u as IdsInput, P as KitSchema, L as ListInput, N as NumberFieldOf, R as ReorderInput, S as ScalarFieldOf, W as WithId, v as admin, c as crud } from './admin-CS7JB_UH.js';
4
+ export { o as ADMIN_DEFAULT_PAGE_SIZE, A as ADMIN_FIELD_TYPES, p as ADMIN_MAX_PAGE, q as ADMIN_MAX_PAGE_SIZE, k as ADMIN_NEVER_WRITABLE, r as AdminCreateInput, s as AdminCreateQuery, t as AdminData, l as AdminFieldConfig, m as AdminFieldType, u as AdminListInput, v as AdminListQuery, w as AdminMetaInput, x as AdminNeverWritable, y as AdminPage, n as AdminServiceMeta, z as AdminSubscribers, B as AdminUpdateInput, C as AdminUpdateQuery, D as AdminWritable, F as FilterValue, L as LIST_DEFAULT_LIMIT, a as LIST_MAX_LIMIT, b as ListPage, c as ListQuery, d as ListSort, S as SEARCH_DEFAULT_LIMIT, e as SEARCH_DEFAULT_MIN_LENGTH, f as SEARCH_MAX_LIMIT, g as SEARCH_MAX_QUERY_LENGTH, h as SearchInput, i as SearchPage, j as SearchQuery, E as SubscriberLevel } from './adminSchemas-29cGgrg5.js';
5
+ export { A as AclMethodName, I as InviteByNameInput, z as InviteByNameQuery, B as InviteInput, C as InviteQuery, L as LeaveInput, D as ListMembersInput, E as ListMembersQuery, F as Member, G as MemberInput, M as MembersMethodName, H as MembersPage, y as SHARE_LEVELS, d as SHARING_METHODS, S as SearchContractOptions, a as SearchDef, b as SearchMethods, c as SearchTag, J as SetRoleInput, K as ShareByNameInput, N as ShareByNameQuery, O as ShareInput, P as ShareLevel, f as SharingByNameMethod, g as SharingContractOptions, h as SharingDefOf, i as SharingInvite, j as SharingInviteByName, k as SharingLeave, l as SharingListMembers, m as SharingListShares, n as SharingMethodName, o as SharingMethods, p as SharingMode, q as SharingRemove, r as SharingSetLevel, t as SharingSetRole, u as SharingShare, v as SharingShareByName, w as SharingTag, x as SharingUnshare, T as TextFieldOf, U as UnshareInput, Q as UserLookupInput, s as search, e as sharing } from './sharing-BrsmlDv_.js';
6
+ export { w as AccessFrame, A as AuthenticationRefused, l as AuthenticationUnavailable, C as CLIENT_EVENTS, x as CallEnvelope, y as CallId, z as CallNotModified, B as CallReply, D as CallSuccess, E as CancelFrame, F as ChangedFrame, G as ChannelFrame, d as ClientEventName, I as ClientToServerEvents, J as CollectionDelta, K as CollectionFrame, L as CollectionItemsReply, M as CollectionItemsRequest, N as CollectionResumed, O as CollectionScopeRef, T as CollectionSnapshot, U as CollectionSubscribe, V as CollectionSubscribeReply, W as EntityFrame, X as EntityNotModified, Y as EntityPatch, Z as EntityRemove, _ as EntityResult, $ as EntityRow, a0 as EntitySubscribe, a1 as EntitySubscribeReply, a2 as EntityUnsubscribe, a3 as EntityUpdate, a4 as EventFrame, a5 as Failure, H as HandshakeAuth, m as HelloFrame, n as HelloLimits, o as HelloPeerLimits, p as HelloSubscriptionLimits, aj as HostChannelMessage, ak as HostFrame, al as HostItem, am as HostMessage, an as HostRefusal, ao as HostSeed, ap as HostSubscribe, aq as HostUnsubscribe, a6 as Ok, P as PROTOCOL_MISMATCH, g as PROTOCOL_VERSION, a7 as PeerCandidate, a8 as PeerData, a9 as PeerDescription, aa as PeerForwardFrame, ab as PeerLabel, ac as PeerMessage, ad as PeerPing, ae as PeerPong, af as PeerSignal, ag as PeerSignalFrame, ah as PresenceFrame, q as ProtocolMismatch, Q as QdHandshake, R as RESERVED_ROOM_PREFIXES, ai as RelayForwardFrame, ar as RelayFrame, as as Revision, au as RevokeReason, at as RevokedFrame, av as RotateFrame, S as SERVER_EVENTS, a as SERVICE_TOPIC, f as ServerEventName, aw as ServerToClientEvents, ax as StreamFrame, ay as StreamSubscribe, az as StreamSubscribeReply, aA as Version, aB as WatchFrame, aC as WireIndexRow, c as collectionRoom, b as collectionTopic, e as entityRoom, i as isAuthenticationRefused, h as isAuthenticationUnavailable, r as isCallEnvelope, v as isCancel, j as isProtocolMismatch, k as isQdHandshake, s as streamRoom, t as topicRoom, u as userRoom } from './envelope-BMBaxppV.js';
7
+ export { T as Tracked, a as TrackedTransaction } from './tracked-BR5b2O-U.js';
7
8
  export { E as ERROR_CODES, a as ErrorCode, Q as QuickdrawError, R as RateLimitedErrorData, V as ValidationErrorData, W as WireError, b as WireIssue, f as fromWire, h as httpStatus, i as isErrorCode, t as toWire } from './errors-S-bxEIBC.js';
8
9
 
9
10
  /** The published version of `@fitzzero/quickdraw-core`. Kept in step with package.json. */
10
- declare const QUICKDRAW_VERSION = "5.1.2";
11
+ declare const QUICKDRAW_VERSION = "5.1.3";
11
12
 
12
13
  export { QUICKDRAW_VERSION };
package/dist/index.js CHANGED
@@ -4,11 +4,31 @@ import {
4
4
  SHARING_METHODS,
5
5
  crud,
6
6
  sharing
7
- } from "./chunk-NMXYENH4.js";
7
+ } from "./chunk-VZFJTKIW.js";
8
8
  import {
9
9
  isCallEnvelope,
10
10
  isCancel
11
- } from "./chunk-RL4VKLBX.js";
11
+ } from "./chunk-KKQANRLG.js";
12
+ import {
13
+ SEARCH_DEFAULT_LIMIT,
14
+ SEARCH_DEFAULT_MIN_LENGTH,
15
+ SEARCH_MAX_LIMIT,
16
+ SEARCH_MAX_QUERY_LENGTH,
17
+ search
18
+ } from "./chunk-XD7SRDUY.js";
19
+ import {
20
+ DEFAULT_COLLECTION_LIMIT,
21
+ DEFAULT_COLLECTION_MAX_LIMIT,
22
+ via
23
+ } from "./chunk-4D2DOGAW.js";
24
+ import {
25
+ ACCESS_LEVELS,
26
+ isAccessLevel
27
+ } from "./chunk-AK23XSWD.js";
28
+ import {
29
+ consoleLogger,
30
+ createConsoleLogger
31
+ } from "./chunk-DKE6QO26.js";
12
32
  import {
13
33
  ADMIN_DEFAULT_PAGE_SIZE,
14
34
  ADMIN_FIELD_TYPES,
@@ -19,22 +39,19 @@ import {
19
39
  CRUD_MAX_IDS,
20
40
  LIST_DEFAULT_LIMIT,
21
41
  LIST_MAX_LIMIT,
22
- SEARCH_DEFAULT_LIMIT,
23
- SEARCH_DEFAULT_MIN_LENGTH,
24
- SEARCH_MAX_LIMIT,
25
- SEARCH_MAX_QUERY_LENGTH,
26
42
  admin,
27
43
  listOf,
28
44
  mutation,
29
45
  nullable,
30
- query,
31
- search
32
- } from "./chunk-GKH3LJ7N.js";
46
+ query
47
+ } from "./chunk-MPQAT55F.js";
48
+ import {
49
+ QUICKDRAW_VERSION
50
+ } from "./chunk-A2RBQD66.js";
33
51
  import {
34
52
  CLIENT_EVENTS,
35
53
  PROTOCOL_MISMATCH,
36
54
  PROTOCOL_VERSION,
37
- QUICKDRAW_VERSION,
38
55
  RESERVED_ROOM_PREFIXES,
39
56
  SERVER_EVENTS,
40
57
  SERVICE_TOPIC,
@@ -42,6 +59,7 @@ import {
42
59
  collectionTopic,
43
60
  entityRoom,
44
61
  isAuthenticationRefused,
62
+ isAuthenticationUnavailable,
45
63
  isProtocolMismatch,
46
64
  isQdHandshake,
47
65
  reservedRoomPrefix,
@@ -49,22 +67,13 @@ import {
49
67
  streamRoom,
50
68
  topicRoom,
51
69
  userRoom
52
- } from "./chunk-753VJIUP.js";
70
+ } from "./chunk-X4ZU4QH5.js";
53
71
  import {
54
72
  CHANNEL_DEFAULT_RATE,
55
73
  GLOBAL_STREAM,
56
74
  STREAM_MAX_SEED,
57
75
  isScopedStream
58
- } from "./chunk-5CGO426C.js";
59
- import {
60
- DEFAULT_COLLECTION_LIMIT,
61
- DEFAULT_COLLECTION_MAX_LIMIT,
62
- via
63
- } from "./chunk-4D2DOGAW.js";
64
- import {
65
- ACCESS_LEVELS,
66
- isAccessLevel
67
- } from "./chunk-AK23XSWD.js";
76
+ } from "./chunk-GYLWEJHW.js";
68
77
  import {
69
78
  TODO_SCHEMA_VENDOR,
70
79
  hasJsonSchema,
@@ -72,10 +81,6 @@ import {
72
81
  todoSchema,
73
82
  validate
74
83
  } from "./chunk-47AEXVDM.js";
75
- import {
76
- consoleLogger,
77
- createConsoleLogger
78
- } from "./chunk-DKE6QO26.js";
79
84
  import {
80
85
  ERROR_CODES,
81
86
  QuickdrawError,
@@ -83,7 +88,8 @@ import {
83
88
  httpStatus,
84
89
  isErrorCode,
85
90
  toWire
86
- } from "./chunk-4YO5H5ON.js";
91
+ } from "./chunk-Q4OGQM5I.js";
92
+ import "./chunk-QSU47XEX.js";
87
93
 
88
94
  // src/contract/validateRealtime.ts
89
95
  var STREAM_KEYS = /* @__PURE__ */ new Set([
@@ -92,6 +98,7 @@ var STREAM_KEYS = /* @__PURE__ */ new Set([
92
98
  "seed",
93
99
  "volatile",
94
100
  "access",
101
+ "serve",
95
102
  "describe"
96
103
  ]);
97
104
  var CHANNEL_KEYS = /* @__PURE__ */ new Set([
@@ -99,6 +106,7 @@ var CHANNEL_KEYS = /* @__PURE__ */ new Set([
99
106
  "ratePerSecond",
100
107
  "burst",
101
108
  "requires",
109
+ "serve",
102
110
  "describe"
103
111
  ]);
104
112
  var EVENT_KEYS = /* @__PURE__ */ new Set(["payload", "describe"]);
@@ -220,14 +228,31 @@ function checkStream(name, value, fail) {
220
228
  if (problem !== void 0) {
221
229
  fail(`${owner}: access ${problem}`);
222
230
  }
223
- const access = stream.access;
224
- const rowForm = isRecord(access) && (access.entry !== void 0 || access.scope !== void 0);
231
+ const access2 = stream.access;
232
+ const rowForm = isRecord(access2) && (access2.entry !== void 0 || access2.scope !== void 0);
225
233
  if (rowForm && !isScopedStream(stream)) {
226
234
  fail(`${owner}: entry and scope access check the scope's row, so the stream needs a scope`);
227
235
  }
228
236
  }
237
+ const { access } = stream;
238
+ const roomOfScope = isRecord(access) && typeof access.room === "function";
239
+ checkServe(
240
+ owner,
241
+ stream,
242
+ isScopedStream(stream) && roomOfScope ? void 0 : "it has a scope, and access { room: (scope) => room }, the room whose host serves each scope",
243
+ fail
244
+ );
229
245
  return Object.freeze({ ...stream });
230
246
  }
247
+ function checkServe(owner, member, needs, fail) {
248
+ const { serve } = member;
249
+ if (serve !== void 0 && serve !== "server" && serve !== "host") {
250
+ fail(`${owner}: serve must be "server" or "host"`);
251
+ }
252
+ if (serve === "host" && needs !== void 0) {
253
+ fail(`${owner} is served by the room's host (serve: "host"): ${needs}`);
254
+ }
255
+ }
231
256
  function isSelector(value) {
232
257
  return isName(value) || typeof value === "function";
233
258
  }
@@ -312,6 +337,13 @@ function checkChannel(name, value, scope, fail) {
312
337
  fail(`${owner}: burst must be a number of messages, at least 1`);
313
338
  }
314
339
  checkRequires(owner, channel.requires, scope, fail);
340
+ const { requires } = channel;
341
+ checkServe(
342
+ owner,
343
+ channel,
344
+ isRecord(requires) && requires.room !== void 0 ? void 0 : "it requires { room }, the room whose host handles its messages",
345
+ fail
346
+ );
315
347
  return Object.freeze({ ...channel });
316
348
  }
317
349
  function checkRealtime(def, scope, fail) {
@@ -748,6 +780,7 @@ export {
748
780
  hasJsonSchema,
749
781
  httpStatus,
750
782
  isAuthenticationRefused,
783
+ isAuthenticationUnavailable,
751
784
  isCallEnvelope,
752
785
  isCancel,
753
786
  isErrorCode,