statewire 0.19.4 → 0.21.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/README.md +15 -1
- package/dist/client/connection.d.ts.map +1 -1
- package/dist/client/connection.js +18 -4
- package/dist/client/connection.js.map +1 -1
- package/dist/client/session.d.ts +10 -1
- package/dist/client/session.d.ts.map +1 -1
- package/dist/client/session.js +92 -27
- package/dist/client/session.js.map +1 -1
- package/dist/client/sessionStore.d.ts +2 -0
- package/dist/client/sessionStore.d.ts.map +1 -1
- package/dist/client/sessionStore.js.map +1 -1
- package/dist/host/host.d.ts +2 -1
- package/dist/host/host.d.ts.map +1 -1
- package/dist/host/host.js +20 -12
- package/dist/host/host.js.map +1 -1
- package/dist/host/http.d.ts.map +1 -1
- package/dist/host/http.js +14 -9
- package/dist/host/http.js.map +1 -1
- package/dist/host/socket.d.ts +14 -3
- package/dist/host/socket.d.ts.map +1 -1
- package/dist/host/socket.js +162 -20
- package/dist/host/socket.js.map +1 -1
- package/dist/host-internal.d.ts +5 -2
- package/dist/host-internal.d.ts.map +1 -1
- package/dist/host.d.ts +6 -0
- package/dist/host.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/statewire.d.ts +3 -0
- package/dist/statewire.d.ts.map +1 -1
- package/dist/statewire.js +23 -5
- package/dist/statewire.js.map +1 -1
- package/dist/transports/remote.d.ts.map +1 -1
- package/dist/transports/remote.js +3 -2
- package/dist/transports/remote.js.map +1 -1
- package/dist/transports/sse.d.ts +5 -0
- package/dist/transports/sse.d.ts.map +1 -1
- package/dist/transports/sse.js +12 -0
- package/dist/transports/sse.js.map +1 -1
- package/dist/transports/testing.d.ts +2 -0
- package/dist/transports/testing.d.ts.map +1 -1
- package/dist/transports/testing.js +11 -4
- package/dist/transports/testing.js.map +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/wire/context.d.ts +14 -0
- package/dist/wire/context.d.ts.map +1 -0
- package/dist/wire/context.js +31 -0
- package/dist/wire/context.js.map +1 -0
- package/dist/wire/limits.d.ts +2 -1
- package/dist/wire/limits.d.ts.map +1 -1
- package/dist/wire/limits.js +2 -1
- package/dist/wire/limits.js.map +1 -1
- package/dist/wire/protocol.d.ts +1 -1
- package/dist/wire/protocol.js +4 -4
- package/dist/wire/protocol.js.map +1 -1
- package/package.json +1 -1
- package/src/client/connection.ts +16 -4
- package/src/client/session.ts +128 -19
- package/src/client/sessionStore.ts +5 -1
- package/src/host/host.ts +18 -3
- package/src/host/http.ts +37 -5
- package/src/host/socket.ts +232 -13
- package/src/host-internal.ts +4 -0
- package/src/host.ts +5 -0
- package/src/statewire.ts +34 -3
- package/src/transports/remote.ts +3 -0
- package/src/transports/sse.ts +19 -0
- package/src/transports/testing.ts +14 -3
- package/src/types.ts +12 -0
- package/src/wire/context.ts +40 -0
- package/src/wire/limits.ts +2 -0
- package/src/wire/protocol.ts +1 -1
package/dist/host/socket.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { encodeDocument, reviveDocumentValue } from "../document.js";
|
|
2
|
+
import { COMMAND_CAPACITY_RETRY_MS, MAX_INFLIGHT_COMMANDS_PER_HOST } from "../wire/limits.js";
|
|
2
3
|
import { DEFAULT_PROTOCOL, WIRE_VERSION, negotiateProtocols } from "../wire/protocol.js";
|
|
4
|
+
import { captureContext, contextValue } from "../wire/context.js";
|
|
3
5
|
import { sanitizeValue } from "../wire/ops.js";
|
|
4
6
|
import { StatewireSendError } from "../types.js";
|
|
5
7
|
import { documentIdentity, getCommandsHost, getStateHost } from "./host.js";
|
|
6
|
-
import { COMMAND_CAPACITY_RETRY_MS, MAX_INFLIGHT_COMMANDS_PER_HOST } from "../wire/limits.js";
|
|
7
8
|
import { createMacrotaskPoster } from "../util/macrotask.js";
|
|
8
9
|
import { frames, stream } from "./http.js";
|
|
9
10
|
import { useEffect, useState } from "@assistant-ui/tap/react-shim";
|
|
@@ -40,11 +41,11 @@ const parseFrameValue = (frame) => {
|
|
|
40
41
|
if (!isPlainObject(frame)) return violation("malformed frame");
|
|
41
42
|
const keys = Object.keys(frame);
|
|
42
43
|
if (keys.length === 0) return violation("malformed frame");
|
|
43
|
-
const unknown = keys.filter((key) => key !== "cmd").sort();
|
|
44
|
+
const unknown = keys.filter((key) => key !== "cmd" && key !== "ctx").sort();
|
|
44
45
|
if (unknown.length > 0) return violation(`unknown frame key: '${unknown[0]}'`);
|
|
45
|
-
const lane = frame["cmd"];
|
|
46
|
+
const lane = frame["cmd"] ?? [];
|
|
46
47
|
if (!Array.isArray(lane)) return violation("malformed frame");
|
|
47
|
-
if (lane.length === 0) return violation("empty lane");
|
|
48
|
+
if (Object.hasOwn(frame, "cmd") && lane.length === 0) return violation("empty lane");
|
|
48
49
|
if (lane.length > 256) return violation("too many commands");
|
|
49
50
|
const prev = /* @__PURE__ */ new Map();
|
|
50
51
|
const cmd = [];
|
|
@@ -65,7 +66,39 @@ const parseFrameValue = (frame) => {
|
|
|
65
66
|
...statement["meta"] !== void 0 && { meta: statement["meta"] }
|
|
66
67
|
});
|
|
67
68
|
}
|
|
68
|
-
|
|
69
|
+
const contexts = frame["ctx"];
|
|
70
|
+
const ctx = [];
|
|
71
|
+
if (contexts !== void 0) {
|
|
72
|
+
if (!Array.isArray(contexts) || contexts.length === 0) return violation("empty context lane");
|
|
73
|
+
const seen = /* @__PURE__ */ new Set();
|
|
74
|
+
for (const entry of contexts) {
|
|
75
|
+
if (!isPlainObject(entry) || typeof entry["protocol"] !== "string" || !Object.hasOwn(entry, "value") || Object.keys(entry).some((key) => ![
|
|
76
|
+
"protocol",
|
|
77
|
+
"value",
|
|
78
|
+
"meta"
|
|
79
|
+
].includes(key))) return violation("malformed context");
|
|
80
|
+
const protocol = entry["protocol"];
|
|
81
|
+
if (seen.has(protocol)) return violation("duplicate context protocol");
|
|
82
|
+
seen.add(protocol);
|
|
83
|
+
if (frameEncoder.encode(JSON.stringify(entry)).byteLength > 65536) return violation("context entry too large");
|
|
84
|
+
try {
|
|
85
|
+
ctx.push({
|
|
86
|
+
protocol,
|
|
87
|
+
value: contextValue({
|
|
88
|
+
value: entry["value"],
|
|
89
|
+
...entry["meta"] !== void 0 && { meta: entry["meta"] }
|
|
90
|
+
})
|
|
91
|
+
});
|
|
92
|
+
} catch (error) {
|
|
93
|
+
return violation(error instanceof Error ? error.message : "invalid context");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (cmd.length === 0 && ctx.length === 0) return violation("empty frame");
|
|
98
|
+
return {
|
|
99
|
+
cmd,
|
|
100
|
+
...ctx.length > 0 && { ctx }
|
|
101
|
+
};
|
|
69
102
|
};
|
|
70
103
|
const parseFrame = (raw) => {
|
|
71
104
|
let frame;
|
|
@@ -116,11 +149,13 @@ const cmdOf = (adm, outcome) => {
|
|
|
116
149
|
...encodePayload(failure.payload)
|
|
117
150
|
};
|
|
118
151
|
}
|
|
119
|
-
default:
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
152
|
+
default:
|
|
153
|
+
console.error("statewire command failed", outcome.error);
|
|
154
|
+
return {
|
|
155
|
+
...at,
|
|
156
|
+
type: "failed",
|
|
157
|
+
message: "the command failed"
|
|
158
|
+
};
|
|
124
159
|
}
|
|
125
160
|
};
|
|
126
161
|
const parseInitialFrame = (raw) => {
|
|
@@ -178,6 +213,10 @@ const closeConn = (h, conn, code, reason) => {
|
|
|
178
213
|
if (!conn.open) return;
|
|
179
214
|
conn.open = false;
|
|
180
215
|
h.conns.delete(conn);
|
|
216
|
+
if (conn.leaseTimer !== null) {
|
|
217
|
+
clearTimeout(conn.leaseTimer);
|
|
218
|
+
conn.leaseTimer = null;
|
|
219
|
+
}
|
|
181
220
|
try {
|
|
182
221
|
conn.socket.close(code, reason);
|
|
183
222
|
} catch {}
|
|
@@ -196,6 +235,35 @@ const sendTo = (h, conn, data) => {
|
|
|
196
235
|
closeConn(h, conn);
|
|
197
236
|
}
|
|
198
237
|
};
|
|
238
|
+
const expiredAt = (h, authorizedAt) => {
|
|
239
|
+
const now = Date.now();
|
|
240
|
+
return authorizedAt === void 0 || !Number.isFinite(authorizedAt) || authorizedAt < 0 || authorizedAt > now || h.maxLeaseLifetimeMs !== null && now - authorizedAt >= h.maxLeaseLifetimeMs;
|
|
241
|
+
};
|
|
242
|
+
const leaseExpiredFin = JSON.stringify({ fin: {
|
|
243
|
+
reason: "reconnect",
|
|
244
|
+
code: "lease-expired"
|
|
245
|
+
} });
|
|
246
|
+
const expireLease = (h, conn) => {
|
|
247
|
+
if (!conn.open || expiredAt(h, conn.authorizedAt)) {
|
|
248
|
+
if (conn.open) {
|
|
249
|
+
sendTo(h, conn, leaseExpiredFin);
|
|
250
|
+
closeConn(h, conn, 1e3, "lease-expired");
|
|
251
|
+
}
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
return false;
|
|
255
|
+
};
|
|
256
|
+
const armLeaseTimer = (h, conn) => {
|
|
257
|
+
if (conn.leaseTimer !== null) clearTimeout(conn.leaseTimer);
|
|
258
|
+
conn.leaseTimer = null;
|
|
259
|
+
if (h.disposed || h.maxLeaseLifetimeMs === null || expireLease(h, conn)) return;
|
|
260
|
+
const delay = h.maxLeaseLifetimeMs - (Date.now() - conn.authorizedAt);
|
|
261
|
+
conn.leaseTimer = setTimeout(() => {
|
|
262
|
+
conn.leaseTimer = null;
|
|
263
|
+
if (!expireLease(h, conn)) armLeaseTimer(h, conn);
|
|
264
|
+
}, Math.min(delay, 2147483647));
|
|
265
|
+
conn.leaseTimer.unref?.();
|
|
266
|
+
};
|
|
199
267
|
const violate = (h, conn, reason) => {
|
|
200
268
|
sendTo(h, conn, JSON.stringify({ fin: {
|
|
201
269
|
reason: "protocol-error",
|
|
@@ -293,6 +361,13 @@ const attachOf = (h, conn) => {
|
|
|
293
361
|
return entry;
|
|
294
362
|
};
|
|
295
363
|
return {
|
|
364
|
+
get caller() {
|
|
365
|
+
return callerOf(h, h.clients.get(conn.clientId), conn);
|
|
366
|
+
},
|
|
367
|
+
context: (protocol) => {
|
|
368
|
+
requireSelected(protocol);
|
|
369
|
+
return captureContext(conn.contexts.get(protocol) ?? {});
|
|
370
|
+
},
|
|
296
371
|
document: (protocol, key) => {
|
|
297
372
|
if (key === void 0 && protocol === h.protocol.name) return h.stateHost.snapshot();
|
|
298
373
|
const view = viewOf(h, conn);
|
|
@@ -537,6 +612,7 @@ const admitCmd = (h, lane, conn, statement) => {
|
|
|
537
612
|
clientId: rec.id,
|
|
538
613
|
caller: callerOf(h, rec, conn),
|
|
539
614
|
attach: conn.attach,
|
|
615
|
+
context: captureContext(conn.contexts.get(statement.protocol) ?? {}),
|
|
540
616
|
onApplied: () => {
|
|
541
617
|
if (adm.settled || adm.applied) return;
|
|
542
618
|
adm.applied = true;
|
|
@@ -562,7 +638,32 @@ const refusal = (h, conn, retry) => ({
|
|
|
562
638
|
...retry !== void 0 && { retry }
|
|
563
639
|
} }
|
|
564
640
|
});
|
|
641
|
+
const validateContexts = (h, conn, frame) => {
|
|
642
|
+
for (const statement of frame.cmd) {
|
|
643
|
+
if (!selects(conn, statement.protocol)) return violation("unsupported protocol");
|
|
644
|
+
if (conn.selection.protocols.find((p) => p.name === statement.protocol).record === "ephemeral") {
|
|
645
|
+
const through = watermark(h, conn, statement.protocol);
|
|
646
|
+
const first = frame.cmd.find((s) => s.protocol === statement.protocol && s.seq > through);
|
|
647
|
+
if (first && first.seq !== through + 1) return violation("ephemeral lane gap");
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
for (const entry of frame.ctx ?? []) {
|
|
651
|
+
if (!selects(conn, entry.protocol)) return violation("unsupported context protocol");
|
|
652
|
+
try {
|
|
653
|
+
h.current?.validateContext?.(entry.protocol, captureContext(entry.value), conn.attach);
|
|
654
|
+
} catch (error) {
|
|
655
|
+
return violation(error instanceof Error ? error.message : "invalid context");
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
const installContexts = (h, conn, frame) => {
|
|
660
|
+
for (const entry of frame.ctx ?? []) conn.contexts.set(entry.protocol, captureContext(entry.value));
|
|
661
|
+
for (const entry of frame.ctx ?? []) h.current?.contextChanged?.(entry.protocol, captureContext(entry.value), conn.attach);
|
|
662
|
+
};
|
|
565
663
|
const admitFrame = (h, conn, frame) => {
|
|
664
|
+
if (expireLease(h, conn)) return { type: "expired" };
|
|
665
|
+
validateContexts(h, conn, frame);
|
|
666
|
+
installContexts(h, conn, frame);
|
|
566
667
|
const rec = h.clients.get(conn.clientId);
|
|
567
668
|
rec.touched = Date.now();
|
|
568
669
|
const lanes = new Map(frame.cmd.map((s) => [s.protocol, laneOf(h, conn, s.protocol)]));
|
|
@@ -594,6 +695,7 @@ const admitFrame = (h, conn, frame) => {
|
|
|
594
695
|
return refusal(h, conn, retry);
|
|
595
696
|
}
|
|
596
697
|
}
|
|
698
|
+
if (expireLease(h, conn)) return { type: "expired" };
|
|
597
699
|
for (const s of fresh) admitCmd(h, lanes.get(s.protocol), conn, s);
|
|
598
700
|
for (const [protocol, lane] of lanes) {
|
|
599
701
|
const last = fresh.findLast((s) => s.protocol === protocol);
|
|
@@ -608,7 +710,7 @@ const admitFrame = (h, conn, frame) => {
|
|
|
608
710
|
return { type: "ok" };
|
|
609
711
|
};
|
|
610
712
|
const message = (h, conn, data) => {
|
|
611
|
-
if (!conn.open || h.disposed || h.finished !== null) return;
|
|
713
|
+
if (!conn.open || h.disposed || h.finished !== null || expireLease(h, conn)) return;
|
|
612
714
|
if (frameIsOversized(data)) {
|
|
613
715
|
sendTo(h, conn, JSON.stringify({ fin: {
|
|
614
716
|
reason: "protocol-error",
|
|
@@ -626,7 +728,7 @@ const message = (h, conn, data) => {
|
|
|
626
728
|
let admission;
|
|
627
729
|
try {
|
|
628
730
|
const frame = first ? parseInitialFrame(data).frame : parseFrame(data);
|
|
629
|
-
if (frame.cmd.length === 0) return;
|
|
731
|
+
if (frame.cmd.length === 0 && !frame.ctx?.length) return;
|
|
630
732
|
admission = admitFrame(h, conn, frame);
|
|
631
733
|
} catch (error) {
|
|
632
734
|
const reason = violationReason(error);
|
|
@@ -690,7 +792,18 @@ const normalizedHeaders = (headers) => {
|
|
|
690
792
|
};
|
|
691
793
|
const connectAuthorized = (h, clientId, socket, options) => {
|
|
692
794
|
const authorize = h.authorize;
|
|
693
|
-
if (options.authorized === true)
|
|
795
|
+
if (options.authorized === true) {
|
|
796
|
+
if (expiredAt(h, options.authorizedAt)) {
|
|
797
|
+
try {
|
|
798
|
+
socket.send(leaseExpiredFin);
|
|
799
|
+
} catch {}
|
|
800
|
+
try {
|
|
801
|
+
socket.close(1e3, "lease-expired");
|
|
802
|
+
} catch {}
|
|
803
|
+
return null;
|
|
804
|
+
}
|
|
805
|
+
return register(h, clientId, socket, options.authorized === true, options.auth, options.selection, void 0, options.authorizedAt)?.connection ?? null;
|
|
806
|
+
}
|
|
694
807
|
const refuse = (code, reason) => {
|
|
695
808
|
try {
|
|
696
809
|
socket.close(code, reason);
|
|
@@ -781,19 +894,20 @@ const connectAuthorized = (h, clientId, socket, options) => {
|
|
|
781
894
|
pending.authorizing = true;
|
|
782
895
|
Promise.resolve().then(() => authorize?.({ headers })).then((auth) => {
|
|
783
896
|
if (!pending.open || h.disposed || h.finished !== null) return;
|
|
897
|
+
const authorizedAt = Date.now();
|
|
784
898
|
const selection = negotiateProtocols(new Headers(headers), h.wireVersion, [h.protocol]);
|
|
785
899
|
if ("fin" in selection) {
|
|
786
900
|
sendPending(pending, JSON.stringify(selection));
|
|
787
901
|
closePending(h, pending, 1008, selection.fin.message);
|
|
788
902
|
return;
|
|
789
903
|
}
|
|
790
|
-
options.onAuthorized?.(auth, selection);
|
|
904
|
+
options.onAuthorized?.(auth, selection, authorizedAt);
|
|
791
905
|
pending.open = false;
|
|
792
906
|
h.pendingConns.delete(pending);
|
|
793
907
|
if (pending.timer !== null) clearTimeout(pending.timer);
|
|
794
908
|
let registration;
|
|
795
909
|
try {
|
|
796
|
-
registration = register(h, clientId, socket, true, auth, selection, frame);
|
|
910
|
+
registration = register(h, clientId, socket, true, auth, selection, frame, authorizedAt);
|
|
797
911
|
} catch (error) {
|
|
798
912
|
if (violationReason(error) === null) throw error;
|
|
799
913
|
return;
|
|
@@ -837,7 +951,7 @@ const register = (h, clientId, socket, sawFrame = false, auth = void 0, selectio
|
|
|
837
951
|
name: h.protocol.name,
|
|
838
952
|
version: h.protocol.version
|
|
839
953
|
}]
|
|
840
|
-
}, frame = { cmd: [] }) => {
|
|
954
|
+
}, frame = { cmd: [] }, authorizedAt) => {
|
|
841
955
|
const refuse = (code, reason) => {
|
|
842
956
|
try {
|
|
843
957
|
socket.close(code, reason);
|
|
@@ -855,6 +969,12 @@ const register = (h, clientId, socket, sawFrame = false, auth = void 0, selectio
|
|
|
855
969
|
return null;
|
|
856
970
|
}
|
|
857
971
|
if (atSubscriberLimit(h)) return refuseSubscriberLimit(socket);
|
|
972
|
+
if (expiredAt(h, authorizedAt)) {
|
|
973
|
+
try {
|
|
974
|
+
socket.send(leaseExpiredFin);
|
|
975
|
+
} catch {}
|
|
976
|
+
return refuse(1e3, "lease-expired");
|
|
977
|
+
}
|
|
858
978
|
const known = h.clients.get(clientId);
|
|
859
979
|
if (known !== void 0 && !authEquals(known.principal, auth)) {
|
|
860
980
|
try {
|
|
@@ -887,7 +1007,10 @@ const register = (h, clientId, socket, sawFrame = false, auth = void 0, selectio
|
|
|
887
1007
|
lastSentAt: 0,
|
|
888
1008
|
lease: null,
|
|
889
1009
|
auth,
|
|
1010
|
+
authorizedAt,
|
|
1011
|
+
leaseTimer: null,
|
|
890
1012
|
lanes: /* @__PURE__ */ new Map(),
|
|
1013
|
+
contexts: /* @__PURE__ */ new Map(),
|
|
891
1014
|
documents: /* @__PURE__ */ new Map(),
|
|
892
1015
|
included: /* @__PURE__ */ new Set(),
|
|
893
1016
|
view: /* @__PURE__ */ new Map(),
|
|
@@ -899,13 +1022,19 @@ const register = (h, clientId, socket, sawFrame = false, auth = void 0, selectio
|
|
|
899
1022
|
conn.attach = attachOf(h, conn);
|
|
900
1023
|
h.conns.add(conn);
|
|
901
1024
|
try {
|
|
1025
|
+
validateContexts(h, conn, frame);
|
|
1026
|
+
installContexts(h, conn, frame);
|
|
902
1027
|
h.current?.attaching?.(conn.attach);
|
|
903
1028
|
} catch (error) {
|
|
904
|
-
|
|
1029
|
+
const reason = violationReason(error);
|
|
1030
|
+
if (reason !== null) violate(h, conn, reason);
|
|
1031
|
+
else closeConn(h, conn, 1011, "attach failed");
|
|
905
1032
|
throw error;
|
|
906
1033
|
}
|
|
907
1034
|
gcClients(h);
|
|
908
1035
|
ensureHeartbeat(h);
|
|
1036
|
+
armLeaseTimer(h, conn);
|
|
1037
|
+
if (!conn.open) return null;
|
|
909
1038
|
const isEphemeral = (s) => selection.protocols.find((p) => p.name === s.protocol)?.record === "ephemeral";
|
|
910
1039
|
const early = frame.cmd.filter(isEphemeral);
|
|
911
1040
|
const late = frame.cmd.filter((s) => !isEphemeral(s));
|
|
@@ -923,6 +1052,7 @@ const register = (h, clientId, socket, sawFrame = false, auth = void 0, selectio
|
|
|
923
1052
|
const earlyAdmission = admit(early);
|
|
924
1053
|
if (early.length > 0) flush(h);
|
|
925
1054
|
notifyClientRecords(h);
|
|
1055
|
+
if (expireLease(h, conn)) return null;
|
|
926
1056
|
const ops = [];
|
|
927
1057
|
if (selects(conn, h.protocol.name)) {
|
|
928
1058
|
const { value, meta } = encodeDocument(h.stateHost.snapshot());
|
|
@@ -981,9 +1111,14 @@ const resume = (h) => {
|
|
|
981
1111
|
h.disposed = false;
|
|
982
1112
|
h.stateHost?.setOnOp((op) => recordOp(h, op));
|
|
983
1113
|
h.stateHost?.setOnDocuments(() => markViews(h));
|
|
1114
|
+
for (const conn of h.conns) armLeaseTimer(h, conn);
|
|
984
1115
|
};
|
|
985
1116
|
const suspend = (h) => {
|
|
986
1117
|
h.disposed = true;
|
|
1118
|
+
for (const conn of h.conns) {
|
|
1119
|
+
if (conn.leaseTimer !== null) clearTimeout(conn.leaseTimer);
|
|
1120
|
+
conn.leaseTimer = null;
|
|
1121
|
+
}
|
|
987
1122
|
if (h.heartbeatTimer !== null) {
|
|
988
1123
|
clearInterval(h.heartbeatTimer);
|
|
989
1124
|
h.heartbeatTimer = null;
|
|
@@ -1017,6 +1152,7 @@ const useSocketHost = (transport, options, persistence) => {
|
|
|
1017
1152
|
key: void 0,
|
|
1018
1153
|
wireVersion: { version: WIRE_VERSION },
|
|
1019
1154
|
heartbeatMs: 15e3,
|
|
1155
|
+
maxLeaseLifetimeMs: 864e5,
|
|
1020
1156
|
wsInitTimeoutMs: 5e3,
|
|
1021
1157
|
maxSubscribers: MAX_SUBSCRIBERS,
|
|
1022
1158
|
maxInflightCommands: MAX_INFLIGHT_COMMANDS_PER_HOST,
|
|
@@ -1054,11 +1190,17 @@ const useSocketHost = (transport, options, persistence) => {
|
|
|
1054
1190
|
});
|
|
1055
1191
|
h.protocol = options?.protocol ?? {
|
|
1056
1192
|
name: "default",
|
|
1057
|
-
version: "2026-09-
|
|
1193
|
+
version: "2026-09-30"
|
|
1058
1194
|
};
|
|
1059
1195
|
h.key = options?.key;
|
|
1060
|
-
h.wireVersion = options?.wireVersion ?? { version: "2026-09-
|
|
1196
|
+
h.wireVersion = options?.wireVersion ?? { version: "2026-09-30" };
|
|
1061
1197
|
setHeartbeatMs(h, options?.heartbeatIntervalMs ?? 15e3);
|
|
1198
|
+
const maxLeaseLifetimeMs = options?.maxLeaseLifetimeMs === void 0 ? 864e5 : options.maxLeaseLifetimeMs;
|
|
1199
|
+
if (maxLeaseLifetimeMs !== null && (!Number.isFinite(maxLeaseLifetimeMs) || maxLeaseLifetimeMs <= 0)) throw new TypeError("maxLeaseLifetimeMs must be finite and positive or null");
|
|
1200
|
+
if (h.maxLeaseLifetimeMs !== maxLeaseLifetimeMs) {
|
|
1201
|
+
h.maxLeaseLifetimeMs = maxLeaseLifetimeMs;
|
|
1202
|
+
for (const conn of [...h.conns]) armLeaseTimer(h, conn);
|
|
1203
|
+
}
|
|
1062
1204
|
h.pushback = options?.pushback;
|
|
1063
1205
|
h.wsInitTimeoutMs = options?.wsInitTimeoutMs ?? 5e3;
|
|
1064
1206
|
const maxSubscribers = options?.maxSubscribers === void 0 ? MAX_SUBSCRIBERS : options.maxSubscribers;
|
|
@@ -1117,6 +1259,6 @@ const StatewireSocketHost = (transport, options, persistence) => {
|
|
|
1117
1259
|
};
|
|
1118
1260
|
};
|
|
1119
1261
|
//#endregion
|
|
1120
|
-
export { CLIENT_ID_RE, PRINCIPAL_MISMATCH_MESSAGE, SUBSCRIBER_LIMIT_MESSAGE, StatewireSocketHost, admitFrame, atSubscriberLimit, authEquals, closeConn, flush, parseFrame, parseFrameValue, register, sendTo };
|
|
1262
|
+
export { CLIENT_ID_RE, PRINCIPAL_MISMATCH_MESSAGE, SUBSCRIBER_LIMIT_MESSAGE, StatewireSocketHost, admitFrame, atSubscriberLimit, authEquals, closeConn, expireLease, flush, parseFrame, parseFrameValue, register, sendTo };
|
|
1121
1263
|
|
|
1122
1264
|
//# sourceMappingURL=socket.js.map
|