experimental-a2 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/dist/actor-DJi3RsNu.d.ts +310 -0
- package/dist/actor-DJi3RsNu.d.ts.map +1 -0
- package/dist/actor-client.d.ts +13 -4
- package/dist/actor-client.d.ts.map +1 -1
- package/dist/actor-client.js +63 -7
- package/dist/actor-client.js.map +1 -1
- package/dist/actor-react.d.ts +5 -4
- package/dist/actor-react.d.ts.map +1 -1
- package/dist/actor-react.js +16 -2
- package/dist/actor-react.js.map +1 -1
- package/dist/actor.d.ts +2 -176
- package/dist/actor.js +13 -2
- package/dist/actor.js.map +1 -1
- package/dist/ai-server.d.ts +1 -1
- package/dist/ai-server.js +2 -2
- package/dist/ai.d.ts +1 -1
- package/dist/ai.js +1 -1
- package/dist/client-Bf6uSEAk.js +1342 -0
- package/dist/client-Bf6uSEAk.js.map +1 -0
- package/dist/client-P_NNNRM-.d.ts +243 -0
- package/dist/client-P_NNNRM-.d.ts.map +1 -0
- package/dist/client.d.ts +2 -208
- package/dist/client.js +2 -1206
- package/dist/errors-DCk6ch5n.js.map +1 -1
- package/dist/errors-DvhSXnxk.d.ts +28 -0
- package/dist/errors-DvhSXnxk.d.ts.map +1 -0
- package/dist/index.d.ts +3 -35
- package/dist/{internal-DRXJ56EI.js → internal-Dq2qYxou.js} +2 -2
- package/dist/{internal-DRXJ56EI.js.map → internal-Dq2qYxou.js.map} +1 -1
- package/dist/platform-B4TnJtWu.js +34 -0
- package/dist/platform-B4TnJtWu.js.map +1 -0
- package/dist/react.d.ts +3 -1
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +2 -1
- package/dist/react.js.map +1 -1
- package/dist/scheduler-qstash.d.ts +2 -2
- package/dist/scheduler-qstash.js +3 -2
- package/dist/scheduler-qstash.js.map +1 -1
- package/dist/scheduler-vercel.d.ts +2 -2
- package/dist/scheduler-vercel.js +2 -2
- package/dist/{server-DlLyvaSH.js → server-BeNADlCI.js} +171 -65
- package/dist/server-BeNADlCI.js.map +1 -0
- package/dist/{server-DgCrSuhB.d.ts → server-DjZZa1wr.d.ts} +9 -3
- package/dist/{server-DgCrSuhB.d.ts.map → server-DjZZa1wr.d.ts.map} +1 -1
- package/dist/server.d.ts +3 -3
- package/dist/server.js +2 -2
- package/dist/{store-DGHeBtIQ.d.ts → store-DtDOWLSn.d.ts} +4 -5
- package/dist/{store-DGHeBtIQ.d.ts.map → store-DtDOWLSn.d.ts.map} +1 -1
- package/dist/store-N8PXxDAS.js.map +1 -1
- package/dist/store-memory.d.ts +1 -1
- package/dist/store-memory.js +1 -1
- package/dist/{store-polling-6DW7F1DT.js → store-polling-CmxUbV93.js} +56 -7
- package/dist/store-polling-CmxUbV93.js.map +1 -0
- package/dist/store-postgres.d.ts +6 -4
- package/dist/store-postgres.d.ts.map +1 -1
- package/dist/store-postgres.js +701 -53
- package/dist/store-postgres.js.map +1 -1
- package/dist/store-presence-polling-C7-XZyW9.js +94 -0
- package/dist/store-presence-polling-C7-XZyW9.js.map +1 -0
- package/dist/store-redis-http.d.ts +2 -2
- package/dist/store-redis-http.d.ts.map +1 -1
- package/dist/store-redis-http.js +184 -38
- package/dist/store-redis-http.js.map +1 -1
- package/dist/{store-redis-core-z-ykbyMg.js → store-redis-notify-BUCyXOn0.js} +491 -27
- package/dist/store-redis-notify-BUCyXOn0.js.map +1 -0
- package/dist/store-redis.d.ts +5 -13
- package/dist/store-redis.d.ts.map +1 -1
- package/dist/store-redis.js +27 -271
- package/dist/store-redis.js.map +1 -1
- package/dist/store-sqlite.d.ts +1 -1
- package/dist/store-sqlite.js +1 -1
- package/dist/{wire--yji6mO3.js → wire-BO5wWCb1.js} +18 -16
- package/dist/wire-BO5wWCb1.js.map +1 -0
- package/docs/actors/04-routes.mdx +40 -8
- package/docs/guides/03-react.mdx +52 -10
- package/docs/guides/05-production.mdx +54 -5
- package/docs/guides/09-presence.mdx +12 -7
- package/docs/guides/10-transports.mdx +15 -2
- package/docs/reference/01-api.mdx +124 -17
- package/docs/reference/02-errors.mdx +45 -11
- package/examples/playground/package.json +1 -1
- package/package.json +1 -1
- package/src/actor-client.ts +114 -14
- package/src/actor-react.ts +18 -3
- package/src/actor.ts +16 -1
- package/src/client-errors.ts +51 -0
- package/src/client.ts +253 -96
- package/src/errors.ts +4 -9
- package/src/index.ts +1 -1
- package/src/internal.ts +1 -1
- package/src/postgres-notification-scope.ts +134 -0
- package/src/postgres-notifications.ts +244 -0
- package/src/postgres-pool.ts +65 -0
- package/src/postgres-resources.ts +185 -0
- package/src/presence-recovery.ts +120 -0
- package/src/react.ts +3 -0
- package/src/redis-http-subscriptions.ts +199 -0
- package/src/server.ts +160 -22
- package/src/session-socket.ts +25 -7
- package/src/sse.ts +17 -0
- package/src/store-polling.ts +32 -12
- package/src/store-postgres.ts +292 -75
- package/src/store-presence-polling.ts +125 -0
- package/src/store-redis-core.ts +37 -30
- package/src/store-redis-http.ts +51 -45
- package/src/store-redis-notify.ts +464 -0
- package/src/store-redis.ts +9 -364
- package/src/store.ts +3 -4
- package/src/stream-activity.ts +32 -0
- package/src/wire.ts +39 -15
- package/dist/actor-shared-USo5MyuF.d.ts +0 -136
- package/dist/actor-shared-USo5MyuF.d.ts.map +0 -1
- package/dist/actor.d.ts.map +0 -1
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/server-DlLyvaSH.js.map +0 -1
- package/dist/store-polling-6DW7F1DT.js.map +0 -1
- package/dist/store-redis-core-z-ykbyMg.js.map +0 -1
- package/dist/wire--yji6mO3.js.map +0 -1
|
@@ -1,40 +1,10 @@
|
|
|
1
1
|
import { n as validateSync } from "./validate-XKT4FSNn.js";
|
|
2
2
|
import { n as NonRetriableError, r as asStoreUnavailable, t as A2Error } from "./errors-DCk6ch5n.js";
|
|
3
|
-
import { c as STREAM_TIMINGS, g as serverInternals, h as nullProtoRecord, i as POLL_TIMINGS, m as markSchedulerSendFailure, o as RESERVED_PARTICIPANT_IDS, s as SOCKET_TIMINGS, t as DRAIN_TIMINGS } from "./internal-
|
|
4
|
-
import { t as defaultSleep } from "./store-polling-
|
|
5
|
-
import {
|
|
3
|
+
import { c as STREAM_TIMINGS, g as serverInternals, h as nullProtoRecord, i as POLL_TIMINGS, m as markSchedulerSendFailure, o as RESERVED_PARTICIPANT_IDS, s as SOCKET_TIMINGS, t as DRAIN_TIMINGS } from "./internal-Dq2qYxou.js";
|
|
4
|
+
import { i as streamActivities, r as createStreamActivity, t as defaultSleep } from "./store-polling-CmxUbV93.js";
|
|
5
|
+
import { r as platformWaitUntil, t as invocationDeadlineMs } from "./platform-B4TnJtWu.js";
|
|
6
|
+
import { _ as socketErrorAckFor, a as errorToWire, b as socketUnsubscribedFor, g as socketAckFor, h as presenceSnapshotToWire, i as errorStatus, n as asA2Error, p as presencePatchToWire, s as eventToWire, t as SOCKET_PING_FRAME, v as socketFrameFor, y as socketSubscribedFor } from "./wire-BO5wWCb1.js";
|
|
6
7
|
import { t as retryableLazy } from "./retryable-lazy-DZWmHpii.js";
|
|
7
|
-
//#region src/platform.ts
|
|
8
|
-
const SYMBOL_FOR_REQ_CONTEXT = Symbol.for("@vercel/request-context");
|
|
9
|
-
function requestContext() {
|
|
10
|
-
try {
|
|
11
|
-
return Reflect.get(globalThis, SYMBOL_FOR_REQ_CONTEXT)?.get?.() ?? {};
|
|
12
|
-
} catch {
|
|
13
|
-
return {};
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
/** The current invocation's Vercel deployment identity, when available. */
|
|
17
|
-
function platformVercelOidcToken() {
|
|
18
|
-
try {
|
|
19
|
-
const token = requestContext().headers?.["x-vercel-oidc-token"];
|
|
20
|
-
return typeof token === "string" && token.length > 0 ? token : null;
|
|
21
|
-
} catch {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
function platformWaitUntil(promise) {
|
|
26
|
-
try {
|
|
27
|
-
requestContext().waitUntil?.(promise);
|
|
28
|
-
} catch {}
|
|
29
|
-
}
|
|
30
|
-
/** The invocation's termination time in epoch ms, or null if unknowable. */
|
|
31
|
-
function invocationDeadlineMs() {
|
|
32
|
-
const deadline = requestContext().deadline;
|
|
33
|
-
if (deadline === void 0 || deadline === null) return null;
|
|
34
|
-
const ms = new Date(deadline).getTime();
|
|
35
|
-
return Number.isNaN(ms) ? null : ms;
|
|
36
|
-
}
|
|
37
|
-
//#endregion
|
|
38
8
|
//#region src/push-envelope.ts
|
|
39
9
|
/**
|
|
40
10
|
* The push envelope's trust boundary for `{ sessionId, events, presence? }`,
|
|
@@ -242,7 +212,7 @@ const pumpSubscription = async (shell, subscription, frameFor) => {
|
|
|
242
212
|
shell.send(frameFor(value));
|
|
243
213
|
}
|
|
244
214
|
};
|
|
245
|
-
const handleSocketPush = async (shell, target, sessionId, frame, req, ackSessionId, gatePush) => {
|
|
215
|
+
const handleSocketPush = async (shell, target, sessionId, frame, req, ackSessionId, gatePush, activate) => {
|
|
246
216
|
try {
|
|
247
217
|
const events = parsePushEvents(frame["events"]);
|
|
248
218
|
const denial = await gatePush?.(sessionId, events, void 0) ?? null;
|
|
@@ -250,7 +220,9 @@ const handleSocketPush = async (shell, target, sessionId, frame, req, ackSession
|
|
|
250
220
|
shell.send(socketErrorAckFor(req, denial, ackSessionId));
|
|
251
221
|
return;
|
|
252
222
|
}
|
|
223
|
+
activate();
|
|
253
224
|
const appended = await target.append(...events);
|
|
225
|
+
activate();
|
|
254
226
|
shell.send(socketAckFor(req, appended, ackSessionId));
|
|
255
227
|
} catch (error) {
|
|
256
228
|
shell.send(socketErrorAckFor(req, asA2Error(error), ackSessionId));
|
|
@@ -300,7 +272,7 @@ function sessionSocket(sessionId, session, socket, options) {
|
|
|
300
272
|
shell.send(socketErrorAckFor(req, new A2Error("STORE_UNAVAILABLE", "push shed: too many in flight on this socket")));
|
|
301
273
|
return;
|
|
302
274
|
}
|
|
303
|
-
shell.track(handleSocketPush(shell, target, sessionId, frame, req, void 0, options?.gatePush));
|
|
275
|
+
shell.track(handleSocketPush(shell, target, sessionId, frame, req, void 0, options?.gatePush, () => streamActivities.get(subscription.iterator)?.activate()));
|
|
304
276
|
return;
|
|
305
277
|
}
|
|
306
278
|
case "presence":
|
|
@@ -355,29 +327,31 @@ function sessionsSocket(resolve, socket, options) {
|
|
|
355
327
|
if (shell.torn() || subscription.stopped) return;
|
|
356
328
|
retire(id, subscription);
|
|
357
329
|
shell.send(socketUnsubscribedFor(id));
|
|
358
|
-
} catch {
|
|
330
|
+
} catch (error) {
|
|
359
331
|
if (shell.torn() || subscription.stopped) return;
|
|
360
332
|
retire(id, subscription);
|
|
361
|
-
shell.send(socketUnsubscribedFor(id, "stream failed"));
|
|
333
|
+
shell.send(socketUnsubscribedFor(id, "stream failed", asA2Error(error)));
|
|
362
334
|
}
|
|
363
335
|
};
|
|
364
336
|
const startSubscription = async (id, index) => {
|
|
337
|
+
const existing = subscriptions.get(id);
|
|
338
|
+
if (existing) {
|
|
339
|
+
stopSubscription(existing);
|
|
340
|
+
subscriptions.delete(id);
|
|
341
|
+
}
|
|
365
342
|
let session;
|
|
366
343
|
try {
|
|
367
344
|
session = await resolve(id, index);
|
|
368
|
-
} catch {
|
|
369
|
-
if (!shell.torn()) shell.send(socketUnsubscribedFor(id, "stream failed"));
|
|
345
|
+
} catch (error) {
|
|
346
|
+
if (!shell.torn()) shell.send(socketUnsubscribedFor(id, "stream failed", asA2Error(error)));
|
|
370
347
|
return;
|
|
371
348
|
}
|
|
372
349
|
if (shell.torn()) return;
|
|
373
350
|
if (session === null) {
|
|
374
|
-
shell.send(socketUnsubscribedFor(id, "subscribe rejected"));
|
|
351
|
+
shell.send(socketUnsubscribedFor(id, "subscribe rejected", new A2Error("FORBIDDEN", "the subscription is not authorized")));
|
|
375
352
|
return;
|
|
376
353
|
}
|
|
377
|
-
const
|
|
378
|
-
const existing = subscriptions.get(id);
|
|
379
|
-
if (existing) stopSubscription(existing);
|
|
380
|
-
const subscription = socketSubscription(target, index, presence);
|
|
354
|
+
const subscription = socketSubscription(session, index, presence);
|
|
381
355
|
subscriptions.set(id, subscription);
|
|
382
356
|
shell.send(socketSubscribedFor(id));
|
|
383
357
|
runSubscription(id, subscription);
|
|
@@ -392,7 +366,10 @@ function sessionsSocket(resolve, socket, options) {
|
|
|
392
366
|
shell.send(socketErrorAckFor(req, new A2Error("STORE_UNAVAILABLE", "session is not subscribed on this socket"), sessionId));
|
|
393
367
|
return;
|
|
394
368
|
}
|
|
395
|
-
await handleSocketPush(shell, subscription.target, sessionId, frame, req, sessionId, options?.gatePush)
|
|
369
|
+
await handleSocketPush(shell, subscription.target, sessionId, frame, req, sessionId, options?.gatePush, () => {
|
|
370
|
+
const current = subscriptions.get(sessionId);
|
|
371
|
+
if (current) streamActivities.get(current.iterator)?.activate();
|
|
372
|
+
});
|
|
396
373
|
};
|
|
397
374
|
const handlePresence = async (frame, sessionId) => {
|
|
398
375
|
const subscription = subscriptions.get(sessionId);
|
|
@@ -493,7 +470,10 @@ function sseResponse(iterable) {
|
|
|
493
470
|
let deadlineTimer;
|
|
494
471
|
let closed = false;
|
|
495
472
|
let iteratorReturned = false;
|
|
473
|
+
let stopActivity;
|
|
496
474
|
const stopTimers = () => {
|
|
475
|
+
stopActivity?.();
|
|
476
|
+
stopActivity = void 0;
|
|
497
477
|
if (heartbeat !== void 0) clearInterval(heartbeat);
|
|
498
478
|
if (deadlineTimer !== void 0) clearTimeout(deadlineTimer);
|
|
499
479
|
heartbeat = void 0;
|
|
@@ -507,6 +487,15 @@ function sseResponse(iterable) {
|
|
|
507
487
|
const stream = new ReadableStream({
|
|
508
488
|
start(controller) {
|
|
509
489
|
controller.enqueue(encoder.encode(": connected\n\n"));
|
|
490
|
+
const activity = streamActivities.get(iterator);
|
|
491
|
+
if (activity) {
|
|
492
|
+
const announce = (idle) => {
|
|
493
|
+
if (closed) return;
|
|
494
|
+
controller.enqueue(encoder.encode(`event: a2-activity\ndata: ${idle ? "idle" : "active"}\n\n`));
|
|
495
|
+
};
|
|
496
|
+
stopActivity = activity.subscribe(announce);
|
|
497
|
+
if (activity.idle) announce(true);
|
|
498
|
+
}
|
|
510
499
|
heartbeat = setInterval(() => {
|
|
511
500
|
try {
|
|
512
501
|
controller.enqueue(encoder.encode(": ping\n\n"));
|
|
@@ -827,6 +816,9 @@ async function deliverSchedulerAppend(server, task) {
|
|
|
827
816
|
if (!internals) throw new TypeError(`a2 scheduler: server for contract '${task.contract}' cannot receive scheduled appends`);
|
|
828
817
|
await internals.schedulerAppend(task.sessionId, task.events);
|
|
829
818
|
}
|
|
819
|
+
function handler(entry) {
|
|
820
|
+
return typeof entry === "function" ? { handler: entry } : entry;
|
|
821
|
+
}
|
|
830
822
|
const MAX_FAILURES = 10;
|
|
831
823
|
/** Default: how long a presence value survives without a refreshing set. */
|
|
832
824
|
const PRESENCE_TTL_MS = 6e4;
|
|
@@ -978,8 +970,8 @@ function createServer(options) {
|
|
|
978
970
|
for (const [type, entry] of Object.entries(options.handlers ?? {})) {
|
|
979
971
|
if (entry === void 0) continue;
|
|
980
972
|
if (!Object.hasOwn(defs, type)) throw new TypeError(`contract '${name}' has no event type '${type}' — cannot register a handler for it`);
|
|
981
|
-
const
|
|
982
|
-
if (typeof
|
|
973
|
+
const callback = typeof entry === "function" ? entry : entry?.handler;
|
|
974
|
+
if (typeof callback !== "function") throw new TypeError(`handler for '${type}' must be a function`);
|
|
983
975
|
let abortOn = null;
|
|
984
976
|
const spec = typeof entry === "function" ? void 0 : entry.abortOn;
|
|
985
977
|
if (spec !== void 0) {
|
|
@@ -995,7 +987,7 @@ function createServer(options) {
|
|
|
995
987
|
const lane = typeof entry === "function" ? null : entry.lane ?? null;
|
|
996
988
|
if (lane !== null && typeof lane !== "function" && (typeof lane !== "string" || lane.length === 0)) throw new TypeError(`lane for '${type}' must be a non-empty string or a function`);
|
|
997
989
|
handlers.set(type, {
|
|
998
|
-
handler,
|
|
990
|
+
handler: callback,
|
|
999
991
|
abortOn,
|
|
1000
992
|
lane
|
|
1001
993
|
});
|
|
@@ -1405,12 +1397,57 @@ function createServer(options) {
|
|
|
1405
1397
|
createdAt: event.createdAt
|
|
1406
1398
|
});
|
|
1407
1399
|
const streamEvents = (id, startAfter) => {
|
|
1408
|
-
|
|
1400
|
+
let closed = false;
|
|
1401
|
+
let inner;
|
|
1402
|
+
let stopActivity;
|
|
1403
|
+
const activity = createStreamActivity(() => {
|
|
1404
|
+
if (inner && !closed) streamActivities.get(inner)?.activate();
|
|
1405
|
+
});
|
|
1406
|
+
let closing;
|
|
1407
|
+
const close = () => {
|
|
1408
|
+
closed = true;
|
|
1409
|
+
closing ??= (async () => {
|
|
1410
|
+
stopActivity?.();
|
|
1411
|
+
await inner?.return?.();
|
|
1412
|
+
})();
|
|
1413
|
+
return closing;
|
|
1414
|
+
};
|
|
1409
1415
|
const outer = async function* () {
|
|
1410
|
-
const
|
|
1411
|
-
|
|
1416
|
+
const store = await resolveStore();
|
|
1417
|
+
if (closed) return;
|
|
1418
|
+
inner = store.stream(nsId(id), { startAfter })[Symbol.asyncIterator]();
|
|
1419
|
+
const sourceActivity = streamActivities.get(inner);
|
|
1420
|
+
if (sourceActivity) {
|
|
1421
|
+
stopActivity = sourceActivity.subscribe(activity.setIdle);
|
|
1422
|
+
activity.setIdle(sourceActivity.idle);
|
|
1423
|
+
}
|
|
1424
|
+
try {
|
|
1425
|
+
for (;;) {
|
|
1426
|
+
if (closed) return;
|
|
1427
|
+
const result = await inner.next();
|
|
1428
|
+
if (closed || result.done) return;
|
|
1429
|
+
yield toSessionEvent(id, result.value);
|
|
1430
|
+
}
|
|
1431
|
+
} finally {
|
|
1432
|
+
await close();
|
|
1433
|
+
}
|
|
1412
1434
|
};
|
|
1413
|
-
|
|
1435
|
+
const iterator = outer();
|
|
1436
|
+
return { [Symbol.asyncIterator]() {
|
|
1437
|
+
const stream = {
|
|
1438
|
+
next: () => iterator.next(),
|
|
1439
|
+
async return() {
|
|
1440
|
+
await close();
|
|
1441
|
+
return iterator.return(void 0);
|
|
1442
|
+
},
|
|
1443
|
+
async throw(error) {
|
|
1444
|
+
await close();
|
|
1445
|
+
return iterator.throw(error);
|
|
1446
|
+
}
|
|
1447
|
+
};
|
|
1448
|
+
streamActivities.set(stream, activity);
|
|
1449
|
+
return stream;
|
|
1450
|
+
} };
|
|
1414
1451
|
};
|
|
1415
1452
|
const requirePresence = (store) => {
|
|
1416
1453
|
if (!store.presence) throw presenceNotSupported();
|
|
@@ -1462,8 +1499,39 @@ function createServer(options) {
|
|
|
1462
1499
|
*/
|
|
1463
1500
|
const streamWithPresence = (id, startAfter) => {
|
|
1464
1501
|
const ns = nsId(id);
|
|
1502
|
+
let closed = false;
|
|
1503
|
+
let events;
|
|
1504
|
+
let unsubscribe;
|
|
1505
|
+
let sleeper = null;
|
|
1506
|
+
let wakeQueue = null;
|
|
1507
|
+
let presenceInterval = Math.min(POLL_TIMINGS.activeFloorMs, POLL_TIMINGS.idleCeilingMs);
|
|
1508
|
+
let presenceActivityVersion = 0;
|
|
1509
|
+
let stopActivity;
|
|
1510
|
+
const activity = createStreamActivity(() => {
|
|
1511
|
+
if (closed) return;
|
|
1512
|
+
presenceActivityVersion += 1;
|
|
1513
|
+
presenceInterval = Math.min(POLL_TIMINGS.activeFloorMs, POLL_TIMINGS.idleCeilingMs);
|
|
1514
|
+
sleeper?.cancel();
|
|
1515
|
+
if (events) streamActivities.get(events)?.activate();
|
|
1516
|
+
});
|
|
1517
|
+
let closing;
|
|
1518
|
+
const close = () => {
|
|
1519
|
+
closed = true;
|
|
1520
|
+
sleeper?.cancel();
|
|
1521
|
+
wakeQueue?.();
|
|
1522
|
+
closing ??= (async () => {
|
|
1523
|
+
try {
|
|
1524
|
+
stopActivity?.();
|
|
1525
|
+
unsubscribe?.();
|
|
1526
|
+
} finally {
|
|
1527
|
+
await events?.return?.();
|
|
1528
|
+
}
|
|
1529
|
+
})();
|
|
1530
|
+
return closing;
|
|
1531
|
+
};
|
|
1465
1532
|
const outer = async function* () {
|
|
1466
1533
|
const store = await resolveStore();
|
|
1534
|
+
if (closed) return;
|
|
1467
1535
|
const api = requirePresence(store);
|
|
1468
1536
|
const readRows = async () => {
|
|
1469
1537
|
try {
|
|
@@ -1538,8 +1606,9 @@ function createServer(options) {
|
|
|
1538
1606
|
if (fields?.size === 0) painted.delete(patch.participant);
|
|
1539
1607
|
};
|
|
1540
1608
|
const queue = /* @__PURE__ */ new Map();
|
|
1541
|
-
let wakeQueue = null;
|
|
1542
1609
|
const enqueue = (patch) => {
|
|
1610
|
+
if (closed) return;
|
|
1611
|
+
activity.activate();
|
|
1543
1612
|
for (const [field, value] of Object.entries(patch.values)) {
|
|
1544
1613
|
if (value === void 0) continue;
|
|
1545
1614
|
let fields = queue.get(patch.participant);
|
|
@@ -1573,11 +1642,17 @@ function createServer(options) {
|
|
|
1573
1642
|
}
|
|
1574
1643
|
return null;
|
|
1575
1644
|
};
|
|
1576
|
-
const unsubscribe = api.subscribe?.(ns, enqueue);
|
|
1577
|
-
const events = store.stream(ns, { startAfter })[Symbol.asyncIterator]();
|
|
1578
1645
|
let pendingEvent = null;
|
|
1579
1646
|
try {
|
|
1647
|
+
unsubscribe = api.subscribe?.(ns, enqueue);
|
|
1648
|
+
events = store.stream(ns, { startAfter })[Symbol.asyncIterator]();
|
|
1649
|
+
const sourceActivity = streamActivities.get(events);
|
|
1650
|
+
if (sourceActivity) {
|
|
1651
|
+
stopActivity = sourceActivity.subscribe(activity.setIdle);
|
|
1652
|
+
activity.setIdle(sourceActivity.idle);
|
|
1653
|
+
}
|
|
1580
1654
|
const snapshotRows = await readRows();
|
|
1655
|
+
if (closed) return;
|
|
1581
1656
|
for (const row of snapshotRows) {
|
|
1582
1657
|
let fields = painted.get(row.participant);
|
|
1583
1658
|
if (!fields) {
|
|
@@ -1592,9 +1667,11 @@ function createServer(options) {
|
|
|
1592
1667
|
}
|
|
1593
1668
|
yield { snapshot: foldPresenceRows(snapshotRows) };
|
|
1594
1669
|
for (;;) {
|
|
1670
|
+
if (closed) return;
|
|
1595
1671
|
for (;;) {
|
|
1596
1672
|
const patch = dequeue();
|
|
1597
1673
|
if (!patch) break;
|
|
1674
|
+
if (closed) return;
|
|
1598
1675
|
paint(patch);
|
|
1599
1676
|
yield patch;
|
|
1600
1677
|
}
|
|
@@ -1606,28 +1683,57 @@ function createServer(options) {
|
|
|
1606
1683
|
});
|
|
1607
1684
|
woke = await Promise.race([pendingEvent.then(() => "event"), arrival.then(() => "patch")]);
|
|
1608
1685
|
wakeQueue = null;
|
|
1686
|
+
if (closed) return;
|
|
1609
1687
|
if (woke === "patch") continue;
|
|
1610
1688
|
} else {
|
|
1611
|
-
|
|
1689
|
+
sleeper = defaultSleep(presenceInterval);
|
|
1612
1690
|
woke = await Promise.race([pendingEvent.then(() => "event"), sleeper.promise.then(() => "tick")]);
|
|
1613
1691
|
sleeper.cancel();
|
|
1692
|
+
sleeper = null;
|
|
1614
1693
|
}
|
|
1694
|
+
if (closed) return;
|
|
1615
1695
|
if (woke === "event") {
|
|
1616
1696
|
const result = await pendingEvent;
|
|
1617
1697
|
pendingEvent = null;
|
|
1618
|
-
if (result.done) return;
|
|
1698
|
+
if (closed || result.done) return;
|
|
1699
|
+
activity.activate();
|
|
1619
1700
|
yield toSessionEvent(id, result.value);
|
|
1620
1701
|
}
|
|
1621
|
-
if (!
|
|
1702
|
+
if (!closed && !unsubscribe) {
|
|
1703
|
+
const version = presenceActivityVersion;
|
|
1704
|
+
const rows = await readRows();
|
|
1705
|
+
if (closed) return;
|
|
1706
|
+
const patches = diffRows(rows);
|
|
1707
|
+
if (patches.length > 0) activity.activate();
|
|
1708
|
+
else if (version === presenceActivityVersion) presenceInterval = Math.min(presenceInterval * 2, POLL_TIMINGS.idleCeilingMs);
|
|
1709
|
+
for (const patch of patches) {
|
|
1710
|
+
if (closed) return;
|
|
1711
|
+
yield patch;
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1622
1714
|
}
|
|
1623
1715
|
} finally {
|
|
1624
|
-
wakeQueue = null;
|
|
1625
|
-
unsubscribe?.();
|
|
1626
1716
|
pendingEvent?.catch(() => {});
|
|
1627
|
-
await
|
|
1717
|
+
await close();
|
|
1718
|
+
wakeQueue = null;
|
|
1628
1719
|
}
|
|
1629
1720
|
};
|
|
1630
|
-
|
|
1721
|
+
const iterator = outer();
|
|
1722
|
+
return { [Symbol.asyncIterator]() {
|
|
1723
|
+
const stream = {
|
|
1724
|
+
next: () => iterator.next(),
|
|
1725
|
+
async return() {
|
|
1726
|
+
await close();
|
|
1727
|
+
return iterator.return(void 0);
|
|
1728
|
+
},
|
|
1729
|
+
async throw(error) {
|
|
1730
|
+
await close();
|
|
1731
|
+
return iterator.throw(error);
|
|
1732
|
+
}
|
|
1733
|
+
};
|
|
1734
|
+
streamActivities.set(stream, activity);
|
|
1735
|
+
return stream;
|
|
1736
|
+
} };
|
|
1631
1737
|
};
|
|
1632
1738
|
const makeSession = (id, append, trigger) => ({
|
|
1633
1739
|
id,
|
|
@@ -2216,6 +2322,6 @@ function cloneInitial(initial) {
|
|
|
2216
2322
|
}
|
|
2217
2323
|
}
|
|
2218
2324
|
//#endregion
|
|
2219
|
-
export {
|
|
2325
|
+
export { sseResponse as a, setServerFetchHooks as i, deliverSchedulerAppend as n, parsePresenceSibling as o, handler as r, createServer as t };
|
|
2220
2326
|
|
|
2221
|
-
//# sourceMappingURL=server-
|
|
2327
|
+
//# sourceMappingURL=server-BeNADlCI.js.map
|