@collective-intelligence/external-apps-client-sdk 0.1.24 → 0.1.26
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 +9 -1
- package/dist/index.d.ts +9 -5
- package/dist/index.js +19 -8
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -315,8 +315,16 @@ const unsubscribe = realtime.subscribe(
|
|
|
315
315
|
the user who received them: store and resend them unchanged, never parse or
|
|
316
316
|
order them. An id the server cannot read answers `reset`.
|
|
317
317
|
`reset` means the gap was too old to replay: refetch every subscribed topic.
|
|
318
|
+
A connection that opens without an event id, the first one included, starts
|
|
319
|
+
at the present: a change between your initial queries and the open would not
|
|
320
|
+
arrive. So the client resyncs: it calls `onReset` once that connection
|
|
321
|
+
opens, at the next delivery. Expect one extra refetch per page load.
|
|
318
322
|
`onReset` runs at the next delivery instead of its pending changes, so the
|
|
319
|
-
tabs that reset together refetch apart
|
|
323
|
+
tabs that reset together refetch apart; a server `reset` and a resync in one
|
|
324
|
+
delivery call it once. Pass `onReset` for gap-free delivery: without it the
|
|
325
|
+
client cannot recover from a reset or a cursorless open, so it delivers the
|
|
326
|
+
pending changes as they are and a change can be lost. `onAccessChanged` runs
|
|
327
|
+
at once.
|
|
320
328
|
- A connection without a ping for 45 seconds is reopened. Failures, 429 and 503
|
|
321
329
|
back off with full jitter between 1 and 30 seconds; `Retry-After` and the
|
|
322
330
|
server's `retry:` set the lower bound. The server ends each connection after
|
package/dist/index.d.ts
CHANGED
|
@@ -1011,8 +1011,11 @@ type RealtimeClientOptions = Readonly<{
|
|
|
1011
1011
|
/** A number in `[0, 1)` for the backoff jitter. */
|
|
1012
1012
|
random?: () => number;
|
|
1013
1013
|
/**
|
|
1014
|
-
*
|
|
1015
|
-
*
|
|
1014
|
+
* Refetch every subscribed topic: the server could not replay the missed
|
|
1015
|
+
* changes, or a stream opened without a last event id, so changes before it
|
|
1016
|
+
* opened did not arrive. It arrives at the next delivery and replaces its
|
|
1017
|
+
* pending changes. Without it, the client cannot recover from such a gap and
|
|
1018
|
+
* delivers the pending changes instead.
|
|
1016
1019
|
*/
|
|
1017
1020
|
onReset?: () => void;
|
|
1018
1021
|
/** The user's access changed: re-check the session and its capabilities. */
|
|
@@ -1040,9 +1043,10 @@ type RealtimeClient = Readonly<{
|
|
|
1040
1043
|
* One realtime connection per tab for every subscribed topic. The connection
|
|
1041
1044
|
* opens while the page is visible and a topic has a listener; a topic set
|
|
1042
1045
|
* change reconnects after a short debounce, and every reconnect resumes after
|
|
1043
|
-
* the last received event
|
|
1044
|
-
*
|
|
1045
|
-
*
|
|
1046
|
+
* the last received event; a stream that opens without one resets instead.
|
|
1047
|
+
* Changes and resets reach the listeners in one delivery per tab, 250 to
|
|
1048
|
+
* 1000 ms after the first of them: a burst of changes refetches once, and
|
|
1049
|
+
* tabs that reset together refetch apart.
|
|
1046
1050
|
* Connection decisions live in the pure state machine (`./machine`); this
|
|
1047
1051
|
* client only runs its commands.
|
|
1048
1052
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1038,7 +1038,7 @@ const linkTransition = (state, event) => {
|
|
|
1038
1038
|
case "ticketFailed":
|
|
1039
1039
|
case "streamEnded": return retry(state, event.retryMilliseconds);
|
|
1040
1040
|
case "streamOpened": return {
|
|
1041
|
-
commands: [watchdog(link.id)],
|
|
1041
|
+
commands: state.lastEventId === void 0 ? [watchdog(link.id), { type: "resync" }] : [watchdog(link.id)],
|
|
1042
1042
|
state: {
|
|
1043
1043
|
...shared(state),
|
|
1044
1044
|
link,
|
|
@@ -1117,9 +1117,10 @@ const defaultTimers = { schedule: (callback, milliseconds) => {
|
|
|
1117
1117
|
* One realtime connection per tab for every subscribed topic. The connection
|
|
1118
1118
|
* opens while the page is visible and a topic has a listener; a topic set
|
|
1119
1119
|
* change reconnects after a short debounce, and every reconnect resumes after
|
|
1120
|
-
* the last received event
|
|
1121
|
-
*
|
|
1122
|
-
*
|
|
1120
|
+
* the last received event; a stream that opens without one resets instead.
|
|
1121
|
+
* Changes and resets reach the listeners in one delivery per tab, 250 to
|
|
1122
|
+
* 1000 ms after the first of them: a burst of changes refetches once, and
|
|
1123
|
+
* tabs that reset together refetch apart.
|
|
1123
1124
|
* Connection decisions live in the pure state machine (`./machine`); this
|
|
1124
1125
|
* client only runs its commands.
|
|
1125
1126
|
*/
|
|
@@ -1174,6 +1175,15 @@ const createRealtimeClient = (options) => {
|
|
|
1174
1175
|
const scheduleDelivery = () => {
|
|
1175
1176
|
cancelDelivery ??= timers.schedule(deliver, changeWindowMilliseconds + Math.floor(random() * changeJitterMilliseconds));
|
|
1176
1177
|
};
|
|
1178
|
+
/**
|
|
1179
|
+
* Replaces the pending changes with one `onReset` at the next delivery.
|
|
1180
|
+
* Without `onReset` no refetch covers them, so they stay.
|
|
1181
|
+
*/
|
|
1182
|
+
const resync = () => {
|
|
1183
|
+
if (options.onReset === void 0) return;
|
|
1184
|
+
resetPending = true;
|
|
1185
|
+
scheduleDelivery();
|
|
1186
|
+
};
|
|
1177
1187
|
const route = (change) => {
|
|
1178
1188
|
const key = realtimeTopicKey(change.topic);
|
|
1179
1189
|
if (!registrations.has(key)) return;
|
|
@@ -1240,10 +1250,8 @@ const createRealtimeClient = (options) => {
|
|
|
1240
1250
|
if (event.type === "change") {
|
|
1241
1251
|
const change = parseRealtimeChange(event.data);
|
|
1242
1252
|
if (change !== void 0) route(change);
|
|
1243
|
-
} else if (event.type === "reset")
|
|
1244
|
-
|
|
1245
|
-
scheduleDelivery();
|
|
1246
|
-
} else if (event.type === "access-changed") options.onAccessChanged?.();
|
|
1253
|
+
} else if (event.type === "reset") resync();
|
|
1254
|
+
else if (event.type === "access-changed") options.onAccessChanged?.();
|
|
1247
1255
|
},
|
|
1248
1256
|
onOpen: () => {
|
|
1249
1257
|
dispatch({
|
|
@@ -1305,6 +1313,9 @@ const createRealtimeClient = (options) => {
|
|
|
1305
1313
|
resources?.close?.();
|
|
1306
1314
|
return;
|
|
1307
1315
|
}
|
|
1316
|
+
case "resync":
|
|
1317
|
+
resync();
|
|
1318
|
+
return;
|
|
1308
1319
|
}
|
|
1309
1320
|
};
|
|
1310
1321
|
const topicsChanged = () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@collective-intelligence/external-apps-client-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.26",
|
|
4
4
|
"description": "Framework-neutral client for Collective Intelligence external applications.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
"typescript": "5.9.3",
|
|
53
53
|
"ultracite": "7.10.7"
|
|
54
54
|
},
|
|
55
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "8200af5951cee11bdd23c59aba0709412aa8ea62"
|
|
56
56
|
}
|