@fitzzero/quickdraw-core 5.1.1 → 5.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/README.md +1308 -219
  2. package/dist/{admin-DKwkIh5i.d.ts → admin-CS7JB_UH.d.ts} +2 -2
  3. package/dist/{adminSchemas-2DUA_hZ8.d.ts → adminSchemas-29cGgrg5.d.ts} +6 -4
  4. package/dist/{auth-BhWqdyb-.d.ts → auth-DtdYjrZ9.d.ts} +51 -21
  5. package/dist/{caller-CXTFswBO.d.ts → caller-BTwGl7vm.d.ts} +296 -33
  6. package/dist/chunk-2FDSKLBO.js +82 -0
  7. package/dist/chunk-2FDSKLBO.js.map +1 -0
  8. package/dist/{chunk-RT6OILOI.js → chunk-4D2DOGAW.js} +2 -14
  9. package/dist/chunk-4D2DOGAW.js.map +1 -0
  10. package/dist/{chunk-OECZPRPW.js → chunk-64I6MYBC.js} +162 -775
  11. package/dist/chunk-64I6MYBC.js.map +1 -0
  12. package/dist/chunk-7473HK24.js +17 -0
  13. package/dist/chunk-7473HK24.js.map +1 -0
  14. package/dist/chunk-7Y5ROPXL.js +33 -0
  15. package/dist/chunk-7Y5ROPXL.js.map +1 -0
  16. package/dist/chunk-A2RBQD66.js +7 -0
  17. package/dist/chunk-A2RBQD66.js.map +1 -0
  18. package/dist/chunk-AK23XSWD.js +16 -0
  19. package/dist/chunk-AK23XSWD.js.map +1 -0
  20. package/dist/chunk-ASAMUGHG.js +651 -0
  21. package/dist/chunk-ASAMUGHG.js.map +1 -0
  22. package/dist/{chunk-B2P7AZ25.js → chunk-CYE4UBOB.js} +6 -4
  23. package/dist/chunk-CYE4UBOB.js.map +1 -0
  24. package/dist/chunk-DKE6QO26.js +136 -0
  25. package/dist/chunk-DKE6QO26.js.map +1 -0
  26. package/dist/chunk-DNP65TD5.js +832 -0
  27. package/dist/chunk-DNP65TD5.js.map +1 -0
  28. package/dist/{chunk-H23KEFBA.js → chunk-DUBU3BB3.js} +30 -1
  29. package/dist/chunk-DUBU3BB3.js.map +1 -0
  30. package/dist/chunk-GYLWEJHW.js +19 -0
  31. package/dist/chunk-GYLWEJHW.js.map +1 -0
  32. package/dist/{chunk-SHEGLZEP.js → chunk-I3JCFS7H.js} +34 -13
  33. package/dist/chunk-I3JCFS7H.js.map +1 -0
  34. package/dist/{chunk-X5CWPX7H.js → chunk-IIQ3WMJK.js} +13 -2
  35. package/dist/chunk-IIQ3WMJK.js.map +1 -0
  36. package/dist/{chunk-RZTP4IEW.js → chunk-JVTONQFI.js} +6339 -4226
  37. package/dist/chunk-JVTONQFI.js.map +1 -0
  38. package/dist/{chunk-QEKVYG5F.js → chunk-KKQANRLG.js} +2 -2
  39. package/dist/chunk-KKQANRLG.js.map +1 -0
  40. package/dist/{chunk-CDKG4TFA.js → chunk-MPQAT55F.js} +38 -205
  41. package/dist/chunk-MPQAT55F.js.map +1 -0
  42. package/dist/chunk-NO4M6PO5.js +101 -0
  43. package/dist/chunk-NO4M6PO5.js.map +1 -0
  44. package/dist/{chunk-TBMKJ26R.js → chunk-NW6U45HX.js} +3 -1
  45. package/dist/chunk-NW6U45HX.js.map +1 -0
  46. package/dist/chunk-NX2V6SIL.js +202 -0
  47. package/dist/chunk-NX2V6SIL.js.map +1 -0
  48. package/dist/{chunk-ZIVPHYRG.js → chunk-NZHA4TZD.js} +72 -175
  49. package/dist/chunk-NZHA4TZD.js.map +1 -0
  50. package/dist/{chunk-2PWMUVC7.js → chunk-OCZJ4EYV.js} +518 -27
  51. package/dist/chunk-OCZJ4EYV.js.map +1 -0
  52. package/dist/{chunk-REX5YPHX.js → chunk-PHCURHC7.js} +76 -21
  53. package/dist/chunk-PHCURHC7.js.map +1 -0
  54. package/dist/{chunk-4YO5H5ON.js → chunk-Q4OGQM5I.js} +4 -10
  55. package/dist/chunk-Q4OGQM5I.js.map +1 -0
  56. package/dist/chunk-QSU47XEX.js +13 -0
  57. package/dist/chunk-QSU47XEX.js.map +1 -0
  58. package/dist/{chunk-DD4SKCNO.js → chunk-RZXJTDH5.js} +13 -2
  59. package/dist/chunk-RZXJTDH5.js.map +1 -0
  60. package/dist/{chunk-Z2LZ7IZ7.js → chunk-SN3OZVEQ.js} +5 -31
  61. package/dist/chunk-SN3OZVEQ.js.map +1 -0
  62. package/dist/{chunk-4DIQHASK.js → chunk-SQ5VUG77.js} +28 -8
  63. package/dist/chunk-SQ5VUG77.js.map +1 -0
  64. package/dist/chunk-STH5DLQP.js +1192 -0
  65. package/dist/chunk-STH5DLQP.js.map +1 -0
  66. package/dist/{chunk-QCHKWIRS.js → chunk-VZFJTKIW.js} +13 -13
  67. package/dist/{chunk-QCHKWIRS.js.map → chunk-VZFJTKIW.js.map} +1 -1
  68. package/dist/{chunk-VSQBHPWH.js → chunk-X4ZU4QH5.js} +54 -22
  69. package/dist/chunk-X4ZU4QH5.js.map +1 -0
  70. package/dist/chunk-XD7SRDUY.js +188 -0
  71. package/dist/chunk-XD7SRDUY.js.map +1 -0
  72. package/dist/chunk-XH2IZVLT.js +62 -0
  73. package/dist/chunk-XH2IZVLT.js.map +1 -0
  74. package/dist/chunk-Z7I6SONO.js +825 -0
  75. package/dist/chunk-Z7I6SONO.js.map +1 -0
  76. package/dist/cli/quickdraw-docs.js +132 -112
  77. package/dist/cli/quickdraw-docs.js.map +1 -1
  78. package/dist/client/core.d.ts +387 -0
  79. package/dist/client/core.js +109 -0
  80. package/dist/client/index.d.ts +52 -203
  81. package/dist/client/index.js +59 -218
  82. package/dist/client/index.js.map +1 -1
  83. package/dist/{clientTypes-Bc-G8n-U.d.ts → clientTypes-CUUNJwWs.d.ts} +3 -3
  84. package/dist/{connection-Cr1BU07W.d.ts → connection-2EeQ_Et0.d.ts} +22 -11
  85. package/dist/{createServer-CP9eDHZZ.d.ts → createServer-Bx5HOcYK.d.ts} +67 -17
  86. package/dist/{createTestApp-UKVGEmOf.d.ts → createTestApp-DAMANT79.d.ts} +46 -13
  87. package/dist/{envelope-Cp3YcVxC.d.ts → envelope-BMBaxppV.d.ts} +216 -10
  88. package/dist/{http-Djj2Inuu.d.ts → http-YzLAar3w.d.ts} +76 -60
  89. package/dist/index.d.ts +8 -7
  90. package/dist/index.js +82 -25
  91. package/dist/index.js.map +1 -1
  92. package/dist/{infer-Teo1xpsd.d.ts → infer-Br62cnyW.d.ts} +82 -11
  93. package/dist/logger-Yz93KzdV.d.ts +30 -0
  94. package/dist/{metrics-BdBu5o8G.d.ts → metrics-CTVpw0gu.d.ts} +2 -2
  95. package/dist/origins-kvpxnVcW.d.ts +8 -0
  96. package/dist/parser.js +2 -1
  97. package/dist/prisma/index.d.ts +14 -7
  98. package/dist/prisma/index.js +279 -70
  99. package/dist/prisma/index.js.map +1 -1
  100. package/dist/{rateLimit-ZMIZJUZF.js → rateLimit-5RKBFLUR.js} +2 -2
  101. package/dist/rateLimit-5RKBFLUR.js.map +1 -0
  102. package/dist/remote-N7OUAGOW.js +15 -0
  103. package/dist/remote-N7OUAGOW.js.map +1 -0
  104. package/dist/server/auth/index.d.ts +82 -33
  105. package/dist/server/auth/index.js +277 -270
  106. package/dist/server/auth/index.js.map +1 -1
  107. package/dist/server/express/index.d.ts +9 -2
  108. package/dist/server/express/index.js +1 -1
  109. package/dist/server/index.d.ts +268 -84
  110. package/dist/server/index.js +664 -418
  111. package/dist/server/index.js.map +1 -1
  112. package/dist/server/mcp/index.d.ts +89 -27
  113. package/dist/server/mcp/index.js +281 -62
  114. package/dist/server/mcp/index.js.map +1 -1
  115. package/dist/server/otel.d.ts +3 -3
  116. package/dist/{sharing-DVa8W-yR.d.ts → sharing-BrsmlDv_.d.ts} +3 -3
  117. package/dist/testing/client.d.ts +14 -14
  118. package/dist/testing/client.js +19 -10
  119. package/dist/testing/client.js.map +1 -1
  120. package/dist/testing/index.d.ts +50 -13
  121. package/dist/testing/index.js +113 -21
  122. package/dist/testing/index.js.map +1 -1
  123. package/dist/testing/mock.d.ts +5 -5
  124. package/dist/testing/mock.js +17 -9
  125. package/dist/tracked-BR5b2O-U.d.ts +43 -0
  126. package/dist/{types-Cu0vmx7c.d.ts → types-CLRCQGnO.d.ts} +4 -3
  127. package/dist/types-tMagHbjy.d.ts +151 -0
  128. package/dist/utils/index.d.ts +16 -4
  129. package/dist/utils/index.js +6 -3
  130. package/package.json +5 -1
  131. package/dist/chunk-2PWMUVC7.js.map +0 -1
  132. package/dist/chunk-4DIQHASK.js.map +0 -1
  133. package/dist/chunk-4YO5H5ON.js.map +0 -1
  134. package/dist/chunk-B2P7AZ25.js.map +0 -1
  135. package/dist/chunk-CDKG4TFA.js.map +0 -1
  136. package/dist/chunk-DD4SKCNO.js.map +0 -1
  137. package/dist/chunk-H23KEFBA.js.map +0 -1
  138. package/dist/chunk-OECZPRPW.js.map +0 -1
  139. package/dist/chunk-QEKVYG5F.js.map +0 -1
  140. package/dist/chunk-REX5YPHX.js.map +0 -1
  141. package/dist/chunk-RT6OILOI.js.map +0 -1
  142. package/dist/chunk-RZTP4IEW.js.map +0 -1
  143. package/dist/chunk-SHEGLZEP.js.map +0 -1
  144. package/dist/chunk-TBMKJ26R.js.map +0 -1
  145. package/dist/chunk-VSQBHPWH.js.map +0 -1
  146. package/dist/chunk-X5CWPX7H.js.map +0 -1
  147. package/dist/chunk-YSWH776Y.js +0 -13
  148. package/dist/chunk-YSWH776Y.js.map +0 -1
  149. package/dist/chunk-Z2LZ7IZ7.js.map +0 -1
  150. package/dist/chunk-ZIVPHYRG.js.map +0 -1
  151. package/dist/logger-BY28acW-.d.ts +0 -16
  152. /package/dist/{rateLimit-ZMIZJUZF.js.map → client/core.js.map} +0 -0
@@ -1,26 +1,25 @@
1
1
  import {
2
- adminSpecOf,
3
2
  searchSpecOf
4
- } from "./chunk-CDKG4TFA.js";
5
- import {
6
- ACCESS_LEVELS,
7
- CLIENT_EVENTS,
8
- MAX_SUBSCRIBE_IDS,
9
- PROTOCOL_VERSION,
10
- QUICKDRAW_VERSION,
11
- SERVER_EVENTS,
12
- isAuthenticationRefused,
13
- isProtocolMismatch
14
- } from "./chunk-VSQBHPWH.js";
3
+ } from "./chunk-XD7SRDUY.js";
15
4
  import {
16
5
  DEFAULT_COLLECTION_MAX_LIMIT
17
- } from "./chunk-RT6OILOI.js";
6
+ } from "./chunk-4D2DOGAW.js";
18
7
  import {
19
- createJsonParser
20
- } from "./chunk-Z2LZ7IZ7.js";
8
+ ACCESS_LEVELS
9
+ } from "./chunk-AK23XSWD.js";
21
10
  import {
22
11
  consoleLogger
23
- } from "./chunk-YSWH776Y.js";
12
+ } from "./chunk-DKE6QO26.js";
13
+ import {
14
+ DEFAULT_BACKOFF_MS,
15
+ INITIAL_CONNECTION_STATE,
16
+ hostLinksOf,
17
+ isServerDisconnect,
18
+ isSessionRefusal,
19
+ notifyEach,
20
+ retryAfterOf,
21
+ subscriptionLimits
22
+ } from "./chunk-STH5DLQP.js";
24
23
  import {
25
24
  KEY_ROOT,
26
25
  collectionKey,
@@ -28,738 +27,23 @@ import {
28
27
  methodKey,
29
28
  methodKeyPrefix,
30
29
  serviceKeyPrefix
31
- } from "./chunk-X5CWPX7H.js";
30
+ } from "./chunk-IIQ3WMJK.js";
31
+ import {
32
+ adminSpecOf
33
+ } from "./chunk-MPQAT55F.js";
34
+ import {
35
+ CLIENT_EVENTS,
36
+ MAX_SCOPE_LENGTH,
37
+ SERVER_EVENTS
38
+ } from "./chunk-X4ZU4QH5.js";
32
39
  import {
33
40
  QuickdrawError,
34
- fromWire,
41
+ fromWire
42
+ } from "./chunk-Q4OGQM5I.js";
43
+ import {
35
44
  isName,
36
45
  isRecord
37
- } from "./chunk-4YO5H5ON.js";
38
-
39
- // src/client/backoff.ts
40
- var DEFAULT_BACKOFF_MS = 5e3;
41
- var MIN_BACKOFF_MS = 250;
42
- var MAX_BACKOFF_MS = 5 * 60 * 1e3;
43
- var JITTER_RATIO = 0.5;
44
- function retryAfterOf(error) {
45
- const retryAfterMs = isRecord(error.data) ? error.data.retryAfterMs : void 0;
46
- return typeof retryAfterMs === "number" ? retryAfterMs : void 0;
47
- }
48
- function waitFor(retryAfterMs) {
49
- const wait2 = typeof retryAfterMs === "number" && Number.isFinite(retryAfterMs) ? retryAfterMs : DEFAULT_BACKOFF_MS;
50
- return Math.min(Math.max(wait2, MIN_BACKOFF_MS), MAX_BACKOFF_MS);
51
- }
52
- function createBackoff(onChange) {
53
- const until = /* @__PURE__ */ new Map();
54
- const timers = /* @__PURE__ */ new Map();
55
- const windows = () => Object.freeze(Object.fromEntries(until));
56
- function end(kind) {
57
- timers.delete(kind);
58
- until.delete(kind);
59
- onChange(windows());
60
- }
61
- return Object.freeze({
62
- report(kind, retryAfterMs) {
63
- const wait2 = waitFor(retryAfterMs);
64
- const delay = wait2 + Math.random() * wait2 * JITTER_RATIO;
65
- const ends2 = Date.now() + delay;
66
- if (ends2 <= (until.get(kind) ?? 0)) {
67
- return;
68
- }
69
- clearTimeout(timers.get(kind));
70
- until.set(kind, ends2);
71
- timers.set(
72
- kind,
73
- setTimeout(() => {
74
- end(kind);
75
- }, delay)
76
- );
77
- onChange(windows());
78
- },
79
- remaining(kind) {
80
- const ends2 = until.get(kind);
81
- return ends2 === void 0 ? 0 : Math.max(0, ends2 - Date.now());
82
- },
83
- windows,
84
- clear() {
85
- for (const timer of timers.values()) {
86
- clearTimeout(timer);
87
- }
88
- timers.clear();
89
- if (until.size > 0) {
90
- until.clear();
91
- onChange(windows());
92
- }
93
- }
94
- });
95
- }
96
-
97
- // src/client/watch.ts
98
- function topicId(service, topic) {
99
- return `${service}\0${topic}`;
100
- }
101
- function rethrowLater(error) {
102
- queueMicrotask(() => {
103
- throw error;
104
- });
105
- }
106
- function notifyEach(listeners, notify) {
107
- for (const listener of [...listeners]) {
108
- try {
109
- notify(listener);
110
- } catch (error) {
111
- rethrowLater(error);
112
- }
113
- }
114
- }
115
- function oncePerKey(records) {
116
- const keys = /* @__PURE__ */ new Set();
117
- return [...records].filter(({ watch }) => {
118
- if (watch.key === void 0) {
119
- return true;
120
- }
121
- const first = !keys.has(watch.key);
122
- keys.add(watch.key);
123
- return first;
124
- });
125
- }
126
- function modelName(model) {
127
- return `${model.charAt(0).toLowerCase()}${model.slice(1)}`;
128
- }
129
- function concerns(watch, frame) {
130
- const { models } = watch;
131
- if (models === void 0 || !Array.isArray(frame.models)) {
132
- return true;
133
- }
134
- const changed3 = new Set(frame.models.map((model) => modelName(String(model))));
135
- return models.some((model) => changed3.has(modelName(model)));
136
- }
137
- function tell(topic, frame) {
138
- const concerned = [...topic.watches].filter(({ watch }) => concerns(watch, frame));
139
- notifyEach(oncePerKey(concerned), ({ watch }) => {
140
- watch.onChanged(frame);
141
- });
142
- }
143
- function tellJoined(topic) {
144
- const waited = new Set([...topic.holds].map((hold2) => hold2.key));
145
- const unjoined = new Set(topic.unjoinedReads);
146
- topic.unjoinedReads.clear();
147
- const owed = [...topic.watches].filter(
148
- ({ watch, told }) => !told || watch.key !== void 0 && unjoined.has(watch.key)
149
- );
150
- for (const record of owed) {
151
- record.told = true;
152
- }
153
- const toTell = owed.filter(({ watch }) => watch.key === void 0 || !waited.has(watch.key));
154
- notifyEach(oncePerKey(toTell), ({ watch }) => {
155
- watch.onJoined?.();
156
- });
157
- }
158
- function releaseHolds(topic) {
159
- const holds = [...topic.holds];
160
- topic.holds.clear();
161
- for (const hold2 of holds) {
162
- if (topic.state !== "joined" && hold2.key !== void 0) {
163
- topic.unjoinedReads.add(hold2.key);
164
- }
165
- hold2.release();
166
- }
167
- }
168
- function isChangedFrame(value) {
169
- return isRecord(value) && typeof value.s === "string" && typeof value.topic === "string";
170
- }
171
- function retryIn(registry, topic, delayMs) {
172
- clearTimeout(topic.retry);
173
- topic.state = "waiting";
174
- topic.retry = setTimeout(() => {
175
- topic.retry = void 0;
176
- if (registry.topics.get(topic.id) === topic) {
177
- join(registry, topic);
178
- }
179
- }, delayMs);
180
- }
181
- function refused(registry, topic, reply) {
182
- const { host } = registry;
183
- const failure = fromWire(isRecord(reply) ? reply.e : void 0);
184
- if (failure.code === "RATE_LIMITED") {
185
- host.reportRateLimited("subscription", retryAfterOf(failure));
186
- retryIn(registry, topic, host.backoffRemaining("subscription"));
187
- } else {
188
- topic.state = "refused";
189
- }
190
- }
191
- function answered(registry, topic, error, reply) {
192
- if (error !== null) {
193
- if (registry.host.socket.connected) {
194
- retryIn(registry, topic, DEFAULT_BACKOFF_MS);
195
- } else {
196
- topic.state = "waiting";
197
- }
198
- } else if (isRecord(reply) && reply.ok === true) {
199
- topic.state = "joined";
200
- tellJoined(topic);
201
- } else {
202
- refused(registry, topic, reply);
203
- }
204
- releaseHolds(topic);
205
- }
206
- function join(registry, topic) {
207
- const { host } = registry;
208
- clearTimeout(topic.retry);
209
- topic.retry = void 0;
210
- topic.attempt += 1;
211
- const wait2 = host.backoffRemaining("subscription");
212
- if (!host.socket.connected) {
213
- topic.state = "waiting";
214
- releaseHolds(topic);
215
- } else if (wait2 > 0) {
216
- retryIn(registry, topic, wait2);
217
- releaseHolds(topic);
218
- } else {
219
- topic.state = "joining";
220
- const { attempt } = topic;
221
- host.lane.send(CLIENT_EVENTS.watch, topic.frame, (error, reply) => {
222
- if (registry.topics.get(topic.id) === topic && topic.attempt === attempt) {
223
- answered(registry, topic, error, reply);
224
- }
225
- });
226
- }
227
- }
228
- function leave(registry, topic) {
229
- registry.topics.delete(topic.id);
230
- clearTimeout(topic.retry);
231
- clearTimeout(topic.leaving);
232
- topic.leaving = void 0;
233
- topic.attempt += 1;
234
- releaseHolds(topic);
235
- const sent = topic.state === "joining" || topic.state === "joined";
236
- if (sent && registry.host.socket.connected) {
237
- registry.host.socket.emit(CLIENT_EVENTS.unwatch, topic.frame);
238
- }
239
- }
240
- function waitForJoin(registry, wait2) {
241
- const topic = registry.topics.get(topicId(wait2.service, wait2.topic));
242
- if (topic === void 0) {
243
- return void 0;
244
- }
245
- if (topic.state === "joining" && registry.host.socket.connected) {
246
- return new Promise((resolve) => {
247
- topic.holds.add({ key: wait2.key, release: resolve });
248
- });
249
- }
250
- if (topic.state !== "joined" && wait2.key !== void 0) {
251
- topic.unjoinedReads.add(wait2.key);
252
- }
253
- return void 0;
254
- }
255
- function startWatch(registry, watch) {
256
- const id = topicId(watch.service, watch.topic);
257
- const topic = registry.topics.get(id) ?? {
258
- id,
259
- frame: Object.freeze({ s: watch.service, topic: watch.topic }),
260
- watches: /* @__PURE__ */ new Set(),
261
- holds: /* @__PURE__ */ new Set(),
262
- unjoinedReads: /* @__PURE__ */ new Set(),
263
- state: "waiting",
264
- retry: void 0,
265
- leaving: void 0,
266
- attempt: 0
267
- };
268
- registry.topics.set(id, topic);
269
- const kept = topic.leaving !== void 0;
270
- clearTimeout(topic.leaving);
271
- topic.leaving = void 0;
272
- const record = { watch, told: topic.state === "joined" };
273
- topic.watches.add(record);
274
- if (topic.watches.size === 1 && !kept) {
275
- join(registry, topic);
276
- }
277
- return () => {
278
- if (topic.watches.delete(record) && topic.watches.size === 0) {
279
- topic.leaving = setTimeout(() => {
280
- if (topic.watches.size === 0 && registry.topics.get(topic.id) === topic) {
281
- leave(registry, topic);
282
- }
283
- }, 0);
284
- }
285
- };
286
- }
287
- function createTopics(host) {
288
- const registry = { host, topics: /* @__PURE__ */ new Map() };
289
- host.socket.on(SERVER_EVENTS.changed, (frame) => {
290
- const topic = isChangedFrame(frame) ? registry.topics.get(topicId(frame.s, frame.topic)) : void 0;
291
- if (topic !== void 0) {
292
- tell(topic, frame);
293
- }
294
- });
295
- host.socket.on("disconnect", () => {
296
- for (const topic of registry.topics.values()) {
297
- if (topic.state === "joined") {
298
- topic.state = "waiting";
299
- }
300
- }
301
- });
302
- return Object.freeze({
303
- watch: (watch) => startWatch(registry, watch),
304
- waitForJoin: (wait2) => waitForJoin(registry, wait2),
305
- rejoin() {
306
- for (const topic of [...registry.topics.values()]) {
307
- if (topic.watches.size === 0) {
308
- leave(registry, topic);
309
- } else {
310
- join(registry, topic);
311
- }
312
- }
313
- },
314
- stop() {
315
- for (const topic of [...registry.topics.values()]) {
316
- if (topic.watches.size === 0) {
317
- leave(registry, topic);
318
- } else {
319
- clearTimeout(topic.retry);
320
- topic.retry = void 0;
321
- topic.attempt += 1;
322
- topic.state = "waiting";
323
- releaseHolds(topic);
324
- }
325
- }
326
- }
327
- });
328
- }
329
-
330
- // src/client/lane.ts
331
- var DEFAULT_SUBSCRIPTION_LANE = 8;
332
- function positiveInteger(value, fallback) {
333
- return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : fallback;
334
- }
335
- function subscriptionLimits(hello) {
336
- const limits = hello?.limits;
337
- const record = isRecord(limits) ? limits : {};
338
- const lane = isRecord(record.subscriptions) ? record.subscriptions : {};
339
- return {
340
- maxInFlight: positiveInteger(lane.maxInFlight, DEFAULT_SUBSCRIPTION_LANE),
341
- maxSubscribeIds: positiveInteger(record.maxSubscribeIds, MAX_SUBSCRIBE_IDS)
342
- };
343
- }
344
- function notConnected() {
345
- return new Error("The socket is not connected; the event was not sent");
346
- }
347
- function createSubscriptionLane(host) {
348
- const queue = [];
349
- let inFlight = 0;
350
- let backoffTimer;
351
- const answer = (pending, error, reply) => {
352
- notifyEach([pending.done], (done) => {
353
- done(error, reply);
354
- });
355
- };
356
- function sendOne(pending) {
357
- inFlight += 1;
358
- const emitter = host.socket.timeout(host.timeoutMs());
359
- emitter.emit(pending.event, pending.frame, (error, reply) => {
360
- inFlight -= 1;
361
- answer(pending, error, reply);
362
- pump();
363
- });
364
- }
365
- function waitForBackoff(wait2) {
366
- backoffTimer ??= setTimeout(() => {
367
- backoffTimer = void 0;
368
- pump();
369
- }, wait2);
370
- }
371
- function dropAll() {
372
- for (const dropped of queue.splice(0)) {
373
- answer(dropped, notConnected(), void 0);
374
- }
375
- }
376
- function pump() {
377
- const { maxInFlight } = subscriptionLimits(host.hello());
378
- while (queue.length > 0 && inFlight < maxInFlight) {
379
- if (!host.socket.connected) {
380
- dropAll();
381
- return;
382
- }
383
- const wait2 = host.backoffRemaining("subscription");
384
- if (wait2 > 0) {
385
- waitForBackoff(wait2);
386
- return;
387
- }
388
- sendOne(queue.shift());
389
- }
390
- }
391
- return Object.freeze({
392
- send(event, frame, done) {
393
- queue.push({ event, frame, done });
394
- pump();
395
- },
396
- inFlight: () => inFlight,
397
- waiting: () => queue.length,
398
- stop() {
399
- clearTimeout(backoffTimer);
400
- backoffTimer = void 0;
401
- dropAll();
402
- }
403
- });
404
- }
405
-
406
- // src/client/reload.ts
407
- var RELOAD_KEY_PREFIX = "quickdraw:protocol-reload:";
408
- function firstReload(scope, key) {
409
- try {
410
- const storage = scope.sessionStorage;
411
- if (storage === void 0 || storage.getItem(key) !== null) {
412
- return false;
413
- }
414
- storage.setItem(key, String(Date.now()));
415
- return true;
416
- } catch {
417
- return false;
418
- }
419
- }
420
- function reloadOncePerSession(mismatch) {
421
- const scope = globalThis;
422
- const location = scope.location;
423
- if (typeof location?.reload !== "function") {
424
- return;
425
- }
426
- if (firstReload(scope, `${RELOAD_KEY_PREFIX}${mismatch.expected}`)) {
427
- location.reload();
428
- }
429
- }
430
-
431
- // src/client/socket.ts
432
- import { io } from "socket.io-client";
433
- function createSocket(settings, credentials) {
434
- return io(settings.url, {
435
- forceNew: true,
436
- withCredentials: true,
437
- transports: ["websocket", "polling"],
438
- ...settings.binary === true ? {} : { parser: createJsonParser() },
439
- ...settings.socketOptions,
440
- ...settings.transports === void 0 ? {} : { transports: settings.transports },
441
- autoConnect: false,
442
- auth: (send2) => {
443
- send2({ ...credentials(), qd: { protocol: PROTOCOL_VERSION, client: QUICKDRAW_VERSION } });
444
- }
445
- });
446
- }
447
-
448
- // src/client/connection.ts
449
- var DEFAULT_TIMEOUT_MS = 1e4;
450
- var HELLO_TIMEOUT_MARGIN_MS = 2e3;
451
- var INITIAL_CONNECTION_STATE = Object.freeze({
452
- status: "idle",
453
- reconnecting: false,
454
- hello: null,
455
- serviceAccess: null,
456
- refusal: null,
457
- backoff: Object.freeze({})
458
- });
459
- function createStore() {
460
- let state = INITIAL_CONNECTION_STATE;
461
- const listeners = /* @__PURE__ */ new Set();
462
- return {
463
- get: () => state,
464
- set(patch2) {
465
- state = Object.freeze({ ...state, ...patch2 });
466
- for (const listener of [...listeners]) {
467
- listener();
468
- }
469
- },
470
- subscribe(listener) {
471
- listeners.add(listener);
472
- return () => {
473
- listeners.delete(listener);
474
- };
475
- }
476
- };
477
- }
478
- function credentialsOf(auth) {
479
- if (typeof auth === "string") {
480
- return auth === "" ? {} : { token: auth };
481
- }
482
- return auth ?? {};
483
- }
484
- function authKey(auth) {
485
- const sorted = (_key, value) => isRecord(value) ? Object.fromEntries(Object.entries(value).sort(([a], [b]) => a < b ? -1 : 1)) : value;
486
- return JSON.stringify(credentialsOf(auth), sorted);
487
- }
488
- function failBuffered(socket, error) {
489
- const buffered = socket.sendBuffer.splice(0);
490
- const { acks } = socket;
491
- for (const packet of buffered) {
492
- const id = packet.id === void 0 ? void 0 : String(packet.id);
493
- const ack = id === void 0 ? void 0 : acks[id];
494
- if (id !== void 0 && ack !== void 0) {
495
- Reflect.deleteProperty(acks, id);
496
- if (ack.withError === true) {
497
- ack.call(socket, error);
498
- }
499
- }
500
- }
501
- }
502
- function refusalOf(error) {
503
- if (isProtocolMismatch(error.data)) {
504
- return { code: error.data.code, expected: error.data.expected };
505
- }
506
- if (isAuthenticationRefused(error.data)) {
507
- return { code: "UNAUTHENTICATED" };
508
- }
509
- return { code: "REFUSED", message: error.message };
510
- }
511
- var MAX_TIMEOUT_MS = 2147483647;
512
- function isTimeLimit(value) {
513
- return typeof value === "number" && value > 0 && value <= MAX_TIMEOUT_MS;
514
- }
515
- function checkOptions(options) {
516
- if (typeof options.url !== "string" || options.url === "") {
517
- throw new TypeError("createQuickdrawConnection: url must be the server's URL");
518
- }
519
- const { timeoutMs } = options;
520
- if (timeoutMs !== void 0 && !isTimeLimit(timeoutMs)) {
521
- throw new TypeError(
522
- "createQuickdrawConnection: timeoutMs must be a number of milliseconds, above 0 and at most 2^31 - 1"
523
- );
524
- }
525
- return timeoutMs;
526
- }
527
- function defaultTimeout(option, hello) {
528
- if (option !== void 0) {
529
- return option;
530
- }
531
- const limits = hello?.limits;
532
- const serverMs = isRecord(limits) ? limits.callTimeoutMs : void 0;
533
- const fromHello = typeof serverMs === "number" ? serverMs + HELLO_TIMEOUT_MARGIN_MS : void 0;
534
- return isTimeLimit(fromHello) ? fromHello : DEFAULT_TIMEOUT_MS;
535
- }
536
- function createLifecycle(socket, store, backoff, session) {
537
- let opened = false;
538
- let switching = false;
539
- let users = 0;
540
- let closeTimer;
541
- let rotateTimer;
542
- function connect() {
543
- socket.connect();
544
- store.set({ status: "connecting", refusal: null });
545
- }
546
- function reconnect() {
547
- if (!opened) {
548
- return;
549
- }
550
- switching = true;
551
- socket.disconnect();
552
- switching = false;
553
- connect();
554
- }
555
- function open() {
556
- clearTimeout(closeTimer);
557
- closeTimer = void 0;
558
- opened = true;
559
- if (!socket.connected && !socket.active) {
560
- connect();
561
- }
562
- }
563
- function close() {
564
- opened = false;
565
- session.established = false;
566
- session.topics.stop();
567
- session.lane.stop();
568
- clearTimeout(closeTimer);
569
- closeTimer = void 0;
570
- clearTimeout(rotateTimer);
571
- rotateTimer = void 0;
572
- backoff.clear();
573
- failBuffered(
574
- socket,
575
- new QuickdrawError("CANCELLED", "The connection closed before the call was sent")
576
- );
577
- socket.disconnect();
578
- store.set({ status: "idle", reconnecting: false });
579
- }
580
- function retain2() {
581
- users += 1;
582
- open();
583
- let released = false;
584
- return () => {
585
- if (!released) {
586
- released = true;
587
- users -= 1;
588
- if (users === 0) {
589
- closeTimer = setTimeout(close, 0);
590
- }
591
- }
592
- };
593
- }
594
- function rotateWithin(withinMs) {
595
- if (rotateTimer === void 0) {
596
- rotateTimer = setTimeout(() => {
597
- rotateTimer = void 0;
598
- reconnect();
599
- }, Math.random() * withinMs);
600
- }
601
- }
602
- function stoppedStatus() {
603
- if (switching) {
604
- return "connecting";
605
- }
606
- return opened ? "disconnected" : "idle";
607
- }
608
- return { open, close, retain: retain2, reconnect, rotateWithin, stoppedStatus };
609
- }
610
- function sayHello(hellos, entry, hello) {
611
- if (hellos.has(entry) && entry.last !== hello) {
612
- entry.last = hello;
613
- entry.listener(hello);
614
- }
615
- }
616
- function addListener(set, listener) {
617
- set.add(listener);
618
- return () => {
619
- set.delete(listener);
620
- };
621
- }
622
- function listenForHellos(wiring, listener) {
623
- const { hellos, store } = wiring;
624
- const entry = { listener, last: void 0 };
625
- hellos.add(entry);
626
- const { status, hello } = store.get();
627
- if (status === "connected" && hello !== null) {
628
- queueMicrotask(() => {
629
- notifyEach([entry], (current) => {
630
- sayHello(hellos, current, hello);
631
- });
632
- });
633
- }
634
- return () => {
635
- hellos.delete(entry);
636
- };
637
- }
638
- function listenToSocket(wiring) {
639
- const { socket, store, lifecycle, session } = wiring;
640
- socket.on("connect", () => {
641
- const again = session.established;
642
- session.established = true;
643
- store.set({ status: "connected", reconnecting: false, refusal: null });
644
- session.topics.rejoin();
645
- if (again) {
646
- notifyEach(wiring.reconnected, (listener) => {
647
- listener();
648
- });
649
- }
650
- });
651
- socket.on("disconnect", () => {
652
- const status = socket.active ? "connecting" : lifecycle.stoppedStatus();
653
- store.set({ status, reconnecting: status === "connecting" && session.established });
654
- });
655
- socket.on("connect_error", (error) => {
656
- if (socket.active) {
657
- return;
658
- }
659
- const refusal = refusalOf(error);
660
- session.established = false;
661
- store.set({ status: "refused", reconnecting: false, refusal });
662
- if (refusal.code === "PROTOCOL_MISMATCH") {
663
- wiring.onProtocolMismatch(refusal);
664
- }
665
- });
666
- }
667
- function listenToPushes(wiring) {
668
- const { socket, store, lifecycle } = wiring;
669
- socket.on(SERVER_EVENTS.hello, (frame) => {
670
- const grants = isRecord(frame) && isRecord(frame.serviceAccess) ? frame.serviceAccess : null;
671
- store.set({ hello: frame, serviceAccess: grants });
672
- notifyEach(wiring.hellos, (entry) => {
673
- sayHello(wiring.hellos, entry, frame);
674
- });
675
- });
676
- socket.on(SERVER_EVENTS.access, (frame) => {
677
- if (isRecord(frame) && isRecord(frame.serviceAccess)) {
678
- store.set({ serviceAccess: frame.serviceAccess });
679
- }
680
- });
681
- socket.on(SERVER_EVENTS.rotate, (frame) => {
682
- const withinMs = isRecord(frame) ? frame.withinMs : void 0;
683
- if (typeof withinMs === "number" && Number.isFinite(withinMs) && withinMs >= 0) {
684
- lifecycle.rotateWithin(withinMs);
685
- }
686
- });
687
- }
688
- function createQuickdrawConnection(options) {
689
- const timeoutOption = checkOptions(options);
690
- const store = createStore();
691
- const backoff = createBackoff((windows) => {
692
- store.set({ backoff: windows });
693
- });
694
- let auth = options.auth;
695
- let nextId = 0;
696
- const socket = createSocket(options, () => credentialsOf(auth));
697
- const timeoutMs = () => defaultTimeout(timeoutOption, store.get().hello);
698
- const subscriptionLane = createSubscriptionLane({
699
- socket,
700
- timeoutMs,
701
- hello: () => store.get().hello,
702
- backoffRemaining: backoff.remaining
703
- });
704
- const topics = createTopics({
705
- socket,
706
- lane: subscriptionLane,
707
- backoffRemaining: backoff.remaining,
708
- reportRateLimited: backoff.report
709
- });
710
- const session = { established: false, topics, lane: subscriptionLane };
711
- const lifecycle = createLifecycle(socket, store, backoff, session);
712
- const reconnected = /* @__PURE__ */ new Set();
713
- const wiring = {
714
- socket,
715
- store,
716
- lifecycle,
717
- session,
718
- reconnected,
719
- hellos: /* @__PURE__ */ new Set(),
720
- onProtocolMismatch: options.onProtocolMismatch ?? reloadOncePerSession
721
- };
722
- listenToSocket(wiring);
723
- listenToPushes(wiring);
724
- return Object.freeze({
725
- url: options.url,
726
- get timeoutMs() {
727
- return timeoutMs();
728
- },
729
- socket,
730
- subscriptionLane,
731
- getState: store.get,
732
- subscribe: store.subscribe,
733
- open: lifecycle.open,
734
- close: lifecycle.close,
735
- retain: lifecycle.retain,
736
- setAuth(next2) {
737
- if (authKey(next2) === authKey(auth)) {
738
- return false;
739
- }
740
- auth = next2;
741
- session.established = false;
742
- failBuffered(
743
- socket,
744
- new QuickdrawError("CANCELLED", "The credentials changed before the call was sent")
745
- );
746
- store.set({ hello: null, serviceAccess: null });
747
- lifecycle.reconnect();
748
- return true;
749
- },
750
- nextCallId() {
751
- const id = nextId;
752
- nextId = nextId >= Number.MAX_SAFE_INTEGER ? 0 : nextId + 1;
753
- return id;
754
- },
755
- reportRateLimited: backoff.report,
756
- backoffRemaining: backoff.remaining,
757
- onReconnect: (listener) => addListener(reconnected, listener),
758
- onHello: (listener) => listenForHellos(wiring, listener),
759
- watch: topics.watch,
760
- waitForJoin: topics.waitForJoin
761
- });
762
- }
46
+ } from "./chunk-QSU47XEX.js";
763
47
 
764
48
  // src/client/loopGuard.ts
765
49
  var MUTATION_LIMIT = 5;
@@ -1237,10 +521,10 @@ function shownOf(held) {
1237
521
  }));
1238
522
  }
1239
523
  function refusedOf(held) {
1240
- const refused3 = (held ?? []).flatMap(
524
+ const refused2 = (held ?? []).flatMap(
1241
525
  (addition) => addition.refusal === void 0 ? [] : [{ item: addition.item, error: addition.refusal.error, addition }]
1242
526
  );
1243
- return refused3.length === 0 ? NO_REFUSALS : refused3;
527
+ return refused2.length === 0 ? NO_REFUSALS : refused2;
1244
528
  }
1245
529
  function newAddition(service, collection, scope, item, keep2) {
1246
530
  return {
@@ -1269,7 +553,7 @@ function unasked(additions) {
1269
553
  }
1270
554
  function weigh(held, evidence) {
1271
555
  const ending = [];
1272
- let refused3 = false;
556
+ let refused2 = false;
1273
557
  for (const addition of held) {
1274
558
  const outcome = verdict(addition, evidence);
1275
559
  if (outcome === "end") {
@@ -1277,10 +561,10 @@ function weigh(held, evidence) {
1277
561
  } else if (outcome === "refuse" && addition.unknown !== void 0) {
1278
562
  addition.refusal = addition.unknown.refusal;
1279
563
  addition.unknown = void 0;
1280
- refused3 = true;
564
+ refused2 = true;
1281
565
  }
1282
566
  }
1283
- return { ending, refused: refused3 };
567
+ return { ending, refused: refused2 };
1284
568
  }
1285
569
  function createAdditions(queryClient) {
1286
570
  const byScope = /* @__PURE__ */ new Map();
@@ -1596,13 +880,13 @@ function settleScope(layers, ref, evidence) {
1596
880
  if (layers.additions.size === 0) {
1597
881
  return;
1598
882
  }
1599
- const { ending, refused: refused3 } = layers.additions.settle(
883
+ const { ending, refused: refused2 } = layers.additions.settle(
1600
884
  ref.service,
1601
885
  ref.collection,
1602
886
  ref.scope,
1603
887
  evidence
1604
888
  );
1605
- discard(layers, [], ending, refused3 ? [ref.service] : []);
889
+ discard(layers, [], ending, refused2 ? [ref.service] : []);
1606
890
  }
1607
891
  function resetLayers(layers) {
1608
892
  const services = new Set(layers.views.keys());
@@ -1622,7 +906,7 @@ function resetLayers(layers) {
1622
906
  layers.count = 0;
1623
907
  changed(layers, services);
1624
908
  }
1625
- function createStore2(queryClient) {
909
+ function createStore(queryClient) {
1626
910
  const layers = {
1627
911
  byRow: /* @__PURE__ */ new Map(),
1628
912
  additions: createAdditions(queryClient),
@@ -1687,7 +971,7 @@ function createStore2(queryClient) {
1687
971
  function storeOf(queryClient) {
1688
972
  let store = stores.get(queryClient);
1689
973
  if (store === void 0) {
1690
- store = createStore2(queryClient);
974
+ store = createStore(queryClient);
1691
975
  stores.set(queryClient, store);
1692
976
  }
1693
977
  return store;
@@ -1745,6 +1029,25 @@ function createSession(connection, queryClient) {
1745
1029
  });
1746
1030
  }
1747
1031
  });
1032
+ const end = () => {
1033
+ queryClient.removeQueries({ queryKey: [KEY_ROOT] });
1034
+ resetOverlays(queryClient);
1035
+ loadedFor.set(queryClient, { userId: null });
1036
+ notifyEach(listeners, (listener) => {
1037
+ listener({ switched: true, first: false });
1038
+ });
1039
+ };
1040
+ const { socket } = connection;
1041
+ socket.on("disconnect", (reason) => {
1042
+ if (isServerDisconnect(reason)) {
1043
+ end();
1044
+ }
1045
+ });
1046
+ socket.on("connect_error", (error) => {
1047
+ if (!socket.active && isRecord(error) && isSessionRefusal(error.data)) {
1048
+ end();
1049
+ }
1050
+ });
1748
1051
  return Object.freeze({
1749
1052
  onHello(listener) {
1750
1053
  listeners.add(listener);
@@ -2445,13 +1748,87 @@ function setState(feeds, feed, state) {
2445
1748
  listener();
2446
1749
  });
2447
1750
  }
2448
- function answered2(feeds, feed, reply) {
1751
+ function answered(feeds, feed, reply) {
2449
1752
  const seed = Array.isArray(reply.seed) ? reply.seed : [];
2450
1753
  const items = latest([...seed, ...feed.pending ?? []], capOf(feed));
2451
1754
  feed.pending = void 0;
2452
1755
  setState(feeds, feed, Object.freeze({ items, isLoading: false, error: null }));
2453
1756
  }
1757
+ var HOST_RETRY_MS = 1e3;
1758
+ function subscribeHost(feeds, feed) {
1759
+ clearTimeout(feed.retry);
1760
+ feed.retry = void 0;
1761
+ feed.release?.();
1762
+ feed.release = void 0;
1763
+ feed.attempt += 1;
1764
+ const { attempt } = feed;
1765
+ const current = () => feed.attempt === attempt && feeds.registry.get(feed.key) === feed;
1766
+ const { s: service, stream } = feed.frame;
1767
+ const scope = feed.frame.scope ?? "";
1768
+ const refused2 = (error) => {
1769
+ feed.pending = void 0;
1770
+ setState(feeds, feed, Object.freeze({ items: [], isLoading: false, error }));
1771
+ };
1772
+ if (!isName(scope) || scope.length > MAX_SCOPE_LENGTH) {
1773
+ refused2(
1774
+ new QuickdrawError(
1775
+ "VALIDATION",
1776
+ `${service}.${stream} is scoped: its scope is a string of 1 to ${MAX_SCOPE_LENGTH} characters`
1777
+ )
1778
+ );
1779
+ return;
1780
+ }
1781
+ if (feed.room === void 0) {
1782
+ refused2(
1783
+ new QuickdrawError(
1784
+ "NOT_FOUND",
1785
+ `No app room serves scope "${scope}" of ${service}.${stream}`
1786
+ )
1787
+ );
1788
+ return;
1789
+ }
1790
+ feed.pending = [];
1791
+ feed.release = hostLinksOf(feeds.host.connection).subscribe(feed.room, {
1792
+ service,
1793
+ stream,
1794
+ scope,
1795
+ seeded: (items) => {
1796
+ if (current()) {
1797
+ answered(feeds, feed, { seed: items });
1798
+ }
1799
+ },
1800
+ item: (item) => {
1801
+ if (current()) {
1802
+ receive(feeds, [service, stream, scope, item]);
1803
+ }
1804
+ },
1805
+ refused: (error) => {
1806
+ if (!current()) {
1807
+ return;
1808
+ }
1809
+ if (error.code === "RATE_LIMITED") {
1810
+ feed.retry = setTimeout(
1811
+ () => {
1812
+ subscribeHost(feeds, feed);
1813
+ },
1814
+ HOST_RETRY_MS * (1 + Math.random() / 2)
1815
+ );
1816
+ } else {
1817
+ refused2(new QuickdrawError(error.code, error.message));
1818
+ }
1819
+ },
1820
+ lost: () => {
1821
+ if (current()) {
1822
+ feed.pending = [];
1823
+ }
1824
+ }
1825
+ });
1826
+ }
2454
1827
  function subscribe(feeds, feed) {
1828
+ if (feed.hosted) {
1829
+ subscribeHost(feeds, feed);
1830
+ return;
1831
+ }
2455
1832
  const { host } = feeds;
2456
1833
  clearTimeout(feed.retry);
2457
1834
  feed.retry = void 0;
@@ -2463,7 +1840,7 @@ function subscribe(feeds, feed) {
2463
1840
  return;
2464
1841
  }
2465
1842
  if (outcome.kind === "ok") {
2466
- answered2(feeds, feed, outcome.reply);
1843
+ answered(feeds, feed, outcome.reply);
2467
1844
  } else if (outcome.kind === "refused") {
2468
1845
  feed.pending = void 0;
2469
1846
  setState(feeds, feed, Object.freeze({ items: [], isLoading: false, error: outcome.error }));
@@ -2481,12 +1858,19 @@ function closeFeed(feeds, feed) {
2481
1858
  const { socket } = feeds.host.connection;
2482
1859
  clearTimeout(feed.retry);
2483
1860
  feed.attempt += 1;
1861
+ if (feed.hosted) {
1862
+ feed.release?.();
1863
+ feed.release = void 0;
1864
+ setState(feeds, feed, PENDING_STREAM);
1865
+ return;
1866
+ }
2484
1867
  if (feed.sent && socket.connected) {
2485
1868
  socket.emit(CLIENT_EVENTS.streamUnsub, feed.frame);
2486
1869
  }
2487
1870
  setState(feeds, feed, PENDING_STREAM);
2488
1871
  }
2489
1872
  function openFeed(target, scope, key) {
1873
+ const { host } = target;
2490
1874
  const frame = scope === void 0 ? { s: target.service, stream: target.stream } : { s: target.service, stream: target.stream, scope };
2491
1875
  return {
2492
1876
  key,
@@ -2496,7 +1880,10 @@ function openFeed(target, scope, key) {
2496
1880
  pending: void 0,
2497
1881
  sent: false,
2498
1882
  attempt: 0,
2499
- retry: void 0
1883
+ retry: void 0,
1884
+ hosted: host !== void 0,
1885
+ room: host?.(scope ?? ""),
1886
+ release: void 0
2500
1887
  };
2501
1888
  }
2502
1889
  function hold(feeds, target, scope, max) {
@@ -2556,6 +1943,7 @@ function listen(feeds, key, listener) {
2556
1943
  };
2557
1944
  }
2558
1945
  function createStreamStore(host) {
1946
+ hostLinksOf(host.connection);
2559
1947
  const feeds = {
2560
1948
  host,
2561
1949
  registry: createRegistry((feed) => {
@@ -2575,7 +1963,9 @@ function createStreamStore(host) {
2575
1963
  },
2576
1964
  resume() {
2577
1965
  for (const feed of feeds.registry.held()) {
2578
- subscribe(feeds, feed);
1966
+ if (!feed.hosted || feed.release === void 0) {
1967
+ subscribe(feeds, feed);
1968
+ }
2579
1969
  }
2580
1970
  },
2581
1971
  forget() {
@@ -2590,6 +1980,10 @@ function createStreamStore(host) {
2590
1980
  feed.retry = void 0;
2591
1981
  feed.attempt += 1;
2592
1982
  feed.pending = void 0;
1983
+ if (feed.hosted) {
1984
+ feed.release?.();
1985
+ feed.release = void 0;
1986
+ }
2593
1987
  }
2594
1988
  }
2595
1989
  });
@@ -2676,15 +2070,15 @@ function loadPage(p) {
2676
2070
  const limit = p.pageLimit();
2677
2071
  const frame = { ...scopeFrame(p), cursor, ...limit === void 0 ? {} : { limit } };
2678
2072
  p.write({ loadingMore: true });
2679
- let answered4 = false;
2073
+ let answered3 = false;
2680
2074
  const page = new Promise((resolve) => {
2681
2075
  request2(p.host, CLIENT_EVENTS.collectionSub, frame, (outcome) => {
2682
- answered4 = true;
2076
+ answered3 = true;
2683
2077
  p.page = void 0;
2684
2078
  resolve(p.disposed ? false : pageLoaded(p, sent, outcome));
2685
2079
  });
2686
2080
  });
2687
- if (!answered4) {
2081
+ if (!answered3) {
2688
2082
  p.page = page;
2689
2083
  }
2690
2084
  return page;
@@ -2857,7 +2251,7 @@ function applyLoad(p, reply, kept, readAt) {
2857
2251
  observeItems(p, reply.items, reply.rev, readAt);
2858
2252
  applied = { state: applySnapshot(base, reply, p.shape), reset: false, missing: [] };
2859
2253
  } else {
2860
- refused2(p, malformed("qd:col:sub"));
2254
+ refused(p, malformed("qd:col:sub"));
2861
2255
  return;
2862
2256
  }
2863
2257
  for (const frame of kept) {
@@ -2881,7 +2275,7 @@ function applyLoad(p, reply, kept, readAt) {
2881
2275
  reloaded
2882
2276
  );
2883
2277
  }
2884
- function refused2(p, error) {
2278
+ function refused(p, error) {
2885
2279
  p.joined = false;
2886
2280
  const drops = ["FORBIDDEN", "NOT_FOUND", "UNAUTHENTICATED"].includes(error.code);
2887
2281
  write(p, drops ? { state: null, error, loadingMore: false } : { error });
@@ -2897,7 +2291,7 @@ function loaded(p, { generation, kind, readAt }, outcome) {
2897
2291
  if (outcome.kind === "ok") {
2898
2292
  applyLoad(p, outcome.reply, kept, readAt);
2899
2293
  } else if (outcome.kind === "refused") {
2900
- refused2(p, outcome.error);
2294
+ refused(p, outcome.error);
2901
2295
  } else if (outcome.kind === "retry") {
2902
2296
  p.retryTimer = setTimeout(() => {
2903
2297
  p.retryTimer = void 0;
@@ -3446,8 +2840,8 @@ function entityResultOf(value) {
3446
2840
  if (isRecord(value) && value.ok === false) {
3447
2841
  return value;
3448
2842
  }
3449
- const answered4 = isRecord(value) && value.ok === true && isRevision(value.rev) && (value.nm === true || Object.hasOwn(value, "d"));
3450
- return answered4 ? value : { ok: false, e: { code: "INTERNAL", message: "The server's qd:sub reply is malformed" } };
2843
+ const answered3 = isRecord(value) && value.ok === true && isRevision(value.rev) && (value.nm === true || Object.hasOwn(value, "d"));
2844
+ return answered3 ? value : { ok: false, e: { code: "INTERNAL", message: "The server's qd:sub reply is malformed" } };
3451
2845
  }
3452
2846
 
3453
2847
  // src/client/live/entityStore.ts
@@ -3529,7 +2923,7 @@ function apply(state, batch, results) {
3529
2923
  commit(state, row, before, applyEntityResult(before, result, batch.readAt));
3530
2924
  });
3531
2925
  }
3532
- function answered3(state, batch, outcome) {
2926
+ function answered2(state, batch, outcome) {
3533
2927
  if (batch.epoch !== state.epoch || outcome.kind === "offline") {
3534
2928
  return;
3535
2929
  }
@@ -3548,7 +2942,7 @@ function send(state, service, ids) {
3548
2942
  const batch = { service, ids, epoch: state.epoch, readAt: state.host.overlays.now() };
3549
2943
  const frame = revs.some((rev) => rev !== null) ? { s: service, ids, revs } : { s: service, ids };
3550
2944
  request2(state.host, CLIENT_EVENTS.sub, frame, (outcome) => {
3551
- answered3(state, batch, outcome);
2945
+ answered2(state, batch, outcome);
3552
2946
  });
3553
2947
  }
3554
2948
  function flush(state) {
@@ -4221,13 +3615,6 @@ function showCollection(state, options) {
4221
3615
  }
4222
3616
 
4223
3617
  export {
4224
- DEFAULT_BACKOFF_MS,
4225
- retryAfterOf,
4226
- notifyEach,
4227
- DEFAULT_SUBSCRIPTION_LANE,
4228
- reloadOncePerSession,
4229
- isTimeLimit,
4230
- createQuickdrawConnection,
4231
3618
  createMutationTrace,
4232
3619
  loopGuardOf,
4233
3620
  DEFAULT_INVALIDATION_WINDOW_MS,
@@ -4284,4 +3671,4 @@ export {
4284
3671
  viewPredicate,
4285
3672
  showCollection
4286
3673
  };
4287
- //# sourceMappingURL=chunk-OECZPRPW.js.map
3674
+ //# sourceMappingURL=chunk-64I6MYBC.js.map