@argentic/chest-sdk 0.4.0 → 0.5.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.
Files changed (80) hide show
  1. package/README.md +508 -80
  2. package/client/index.ts +11 -7
  3. package/client/src/api.ts +19 -18
  4. package/client/src/database.ts +6 -1
  5. package/client/src/errors.ts +50 -0
  6. package/client/src/eventrules.ts +117 -0
  7. package/client/src/events.ts +181 -39
  8. package/client/src/files.ts +37 -7
  9. package/client/src/member.ts +15 -9
  10. package/client/src/members.ts +34 -16
  11. package/client/src/notifications.ts +84 -27
  12. package/client/src/realtime-client.ts +516 -0
  13. package/client/src/realtime.ts +118 -0
  14. package/client/src/sealed.ts +158 -0
  15. package/client/src/signed.ts +8 -4
  16. package/client/src/testing-realtime.ts +361 -0
  17. package/client/src/testing.ts +391 -94
  18. package/dist/index.d.ts +2 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +11 -7
  21. package/dist/index.js.map +1 -1
  22. package/dist/src/api.d.ts +2 -1
  23. package/dist/src/api.d.ts.map +1 -1
  24. package/dist/src/api.js +18 -16
  25. package/dist/src/api.js.map +1 -1
  26. package/dist/src/database.d.ts.map +1 -1
  27. package/dist/src/database.js +5 -1
  28. package/dist/src/database.js.map +1 -1
  29. package/dist/src/errors.d.ts +18 -0
  30. package/dist/src/errors.d.ts.map +1 -1
  31. package/dist/src/errors.js +44 -0
  32. package/dist/src/errors.js.map +1 -1
  33. package/dist/src/eventrules.d.ts +23 -0
  34. package/dist/src/eventrules.d.ts.map +1 -0
  35. package/dist/src/eventrules.js +107 -0
  36. package/dist/src/eventrules.js.map +1 -0
  37. package/dist/src/events.d.ts +31 -6
  38. package/dist/src/events.d.ts.map +1 -1
  39. package/dist/src/events.js +130 -26
  40. package/dist/src/events.js.map +1 -1
  41. package/dist/src/files.d.ts +1 -0
  42. package/dist/src/files.d.ts.map +1 -1
  43. package/dist/src/files.js +34 -3
  44. package/dist/src/files.js.map +1 -1
  45. package/dist/src/member.d.ts +1 -1
  46. package/dist/src/member.d.ts.map +1 -1
  47. package/dist/src/member.js +9 -6
  48. package/dist/src/member.js.map +1 -1
  49. package/dist/src/members.d.ts +9 -2
  50. package/dist/src/members.d.ts.map +1 -1
  51. package/dist/src/members.js +29 -13
  52. package/dist/src/members.js.map +1 -1
  53. package/dist/src/notifications.d.ts +12 -1
  54. package/dist/src/notifications.d.ts.map +1 -1
  55. package/dist/src/notifications.js +60 -19
  56. package/dist/src/notifications.js.map +1 -1
  57. package/dist/src/realtime-client.d.ts +45 -0
  58. package/dist/src/realtime-client.d.ts.map +1 -0
  59. package/dist/src/realtime-client.js +453 -0
  60. package/dist/src/realtime-client.js.map +1 -0
  61. package/dist/src/realtime.d.ts +22 -0
  62. package/dist/src/realtime.d.ts.map +1 -0
  63. package/dist/src/realtime.js +99 -0
  64. package/dist/src/realtime.js.map +1 -0
  65. package/dist/src/sealed.d.ts +20 -0
  66. package/dist/src/sealed.d.ts.map +1 -0
  67. package/dist/src/sealed.js +121 -0
  68. package/dist/src/sealed.js.map +1 -0
  69. package/dist/src/signed.d.ts.map +1 -1
  70. package/dist/src/signed.js +6 -2
  71. package/dist/src/signed.js.map +1 -1
  72. package/dist/src/testing-realtime.d.ts +54 -0
  73. package/dist/src/testing-realtime.d.ts.map +1 -0
  74. package/dist/src/testing-realtime.js +376 -0
  75. package/dist/src/testing-realtime.js.map +1 -0
  76. package/dist/src/testing.d.ts +40 -3
  77. package/dist/src/testing.d.ts.map +1 -1
  78. package/dist/src/testing.js +368 -81
  79. package/dist/src/testing.js.map +1 -1
  80. package/package.json +23 -4
@@ -0,0 +1,453 @@
1
+ // The browser's side of a tool's live updates: the one module of the SDK
2
+ // that runs in a page (no node: import, nothing read from the environment).
3
+ // A page of the tool's private part (/chest) connects to the Chest on its
4
+ // own host — the member's session is the identity, no token —, joins the
5
+ // channels its tool declares and hears what reaches them: the rows of its
6
+ // feeds as they are committed and the tool's events (on), the other
7
+ // members' ephemeral messages (peers, never mixed with the Chest's), who is
8
+ // present. The connection is the Chest's: the tool may sleep meanwhile.
9
+ //
10
+ // import { connect } from "@argentic/chest-sdk/realtime/client";
11
+ // const live = connect();
12
+ // const room = live.channel("room:42");
13
+ // room.on("messages.insert", row => show(row));
14
+ // room.onJoined(({ replayed }) => replayed || refetchAfter(lastId)); // joined: fetch, unless what was missed came again
15
+ // room.onResync(() => refetchAfter(lastId)); // what was missed is not all kept: ask the tool
16
+ // room.peers.on("typing", (_, from) => showTyping(from));
17
+ // room.peers.send("typing");
18
+ // room.presence.track({ active: true });
19
+ // room.presence.on(list => showOnline(list));
20
+ // live.focus("room:42"); // the conversation on screen: the tool notifies those not watching it
21
+ // live.on("closed", reason => reason === "access_removed" ? showAccessRemoved() : location.reload());
22
+ //
23
+ // It reconnects by itself, unseen: a cut is told (status false) only once
24
+ // it lasts 3 s; it tries again 0.5 s to 30 s apart — at once when the page
25
+ // comes back to the foreground, from the cache or to the network, never
26
+ // while the browser is offline (going offline drops the connection at
27
+ // once), and no sooner than the Chest asks when it is full —, joins its channels again with where each stood, and the Chest
28
+ // gives what was missed however long the page was away: the tool's events
29
+ // of the last 2 minutes, the feeds' rows of the last 7 days — or says
30
+ // resync. A join the Chest has no room for is tried again with the same
31
+ // backoff, unseen. While connected it renews the member's session every 5
32
+ // minutes.
33
+ // It stops for good when access was removed (closed "access_removed") or
34
+ // the session ended (closed "signed_out": a reload signs in again, silently
35
+ // while the provider's session lasts). Content is the tool's: render it as
36
+ // text, never as HTML.
37
+ // The subprotocol of the Chest's realtime, and where it is.
38
+ const protocol = "chest-realtime.v1";
39
+ const path = "/_chest/realtime";
40
+ // The rhythm: the backoff's first and last delay; the ping that finds a
41
+ // dead network, how long its answer may take, and how long when the page
42
+ // wakes; how often the session is renewed; how long a cut stays untold.
43
+ const firstDelay = 500, lastDelay = 30000, pingEvery = 25000, pingWait = 10000, wakeWait = 5000, renewEvery = 300000, quietFor = 3000;
44
+ // The grammar of a member's message: 1 to 64 of a-z 0-9 _ -, never a dot —
45
+ // dotted names are the tool's and the feeds' ("messages.insert",
46
+ // "rooms.changed"), so a member never speaks as them.
47
+ export const peerEventPattern = /^[a-z0-9_-]{1,64}$/u;
48
+ // listen adds a listener to a set, and returns what removes it.
49
+ function listen(set, listener) {
50
+ set.add(listener);
51
+ return () => { set.delete(listener); };
52
+ }
53
+ // listenTo adds a listener of one event.
54
+ function listenTo(map, event, listener) {
55
+ let set = map.get(event);
56
+ if (!set)
57
+ map.set(event, set = new Set());
58
+ return listen(set, listener);
59
+ }
60
+ // connect connects the page to the Chest — on its own host, or url (a
61
+ // test's) —, and stays connected until closed.
62
+ export function connect(options = {}) {
63
+ const page = globalThis;
64
+ const url = options.url ?? (page.location ? (page.location.protocol === "https:" ? "wss://" : "ws://") + page.location.host + path : "");
65
+ if (!url)
66
+ throw new Error("connect runs in a page of the tool, or is given a url");
67
+ const channels = new Map();
68
+ const direct = new Set();
69
+ const status = new Set();
70
+ const closed = new Set();
71
+ const answers = new Map();
72
+ // connected: the Chest said hello on the socket; asking: a question before
73
+ // connecting is on its way; told: the status the page was last told;
74
+ // focused: the channel the page has on screen, focusSent what the Chest
75
+ // was last told of it on this connection ("" none).
76
+ let socket, ref = 0, attempts = 0, ended = false, connected = false, asking = false;
77
+ let epoch, member, told, focused = null, focusSent = "";
78
+ let timer, quiet, silence;
79
+ let pinger, renewer;
80
+ const emit = (listeners, ...args) => {
81
+ for (const listener of [...listeners]) {
82
+ try {
83
+ listener(...args);
84
+ }
85
+ catch (error) {
86
+ setTimeout(() => { throw error; });
87
+ }
88
+ }
89
+ };
90
+ const fire = (listeners, event, ...args) => {
91
+ const set = listeners.get(event);
92
+ if (set)
93
+ emit(set, ...args);
94
+ };
95
+ const tell = (up) => {
96
+ told = up;
97
+ emit(status, up);
98
+ };
99
+ const presenceChanged = (ch) => emit(ch.presenceListeners, [...ch.present].map(([id, state]) => ({ id, state })));
100
+ const write = (message, answer) => {
101
+ if (!socket || socket.readyState !== 1)
102
+ return false;
103
+ if (answer) {
104
+ ref = ref % 0xffffffff + 1;
105
+ message["ref"] = ref;
106
+ answers.set(ref, answer);
107
+ }
108
+ socket.send(JSON.stringify(message));
109
+ return true;
110
+ };
111
+ // shown: the page is in the foreground (always, without a document).
112
+ const shown = () => (page.document?.visibilityState ?? "visible") === "visible";
113
+ // tellFocus tells the Chest the channel the page has on screen: the one
114
+ // focused once joined and while shown, none otherwise — only when it
115
+ // changes.
116
+ const tellFocus = () => {
117
+ const ch = focused === null ? undefined : channels.get(focused);
118
+ const now = ch?.joined && shown() ? ch.name : "";
119
+ if (now !== focusSent && write({ op: "focus", ch: now }, () => { }))
120
+ focusSent = now;
121
+ };
122
+ // join joins a channel — again, from where it stood: the Chest gives
123
+ // what was missed, then what comes; or says resync. A Chest without room
124
+ // for it is asked again after the backoff, unseen.
125
+ const join = (ch) => {
126
+ const since = ch.epoch === undefined ? undefined : { epoch: ch.epoch, seq: ch.seq, ...(ch.pos > 0 ? { pos: ch.pos } : {}) };
127
+ write({ op: "join", ch: ch.name, ...(since ? { since } : {}) }, answer => {
128
+ if (answer["code"] === "full") {
129
+ ch.retry = setTimeout(() => {
130
+ ch.retry = undefined;
131
+ if (connected && channels.get(ch.name) === ch)
132
+ join(ch);
133
+ }, delay(ch.full++));
134
+ return;
135
+ }
136
+ if (answer["op"] !== "ok") {
137
+ ch.joined = false;
138
+ emit(ch.refusedListeners, String(answer["code"]));
139
+ return;
140
+ }
141
+ ch.joined = true;
142
+ ch.full = 0;
143
+ const replayed = since !== undefined && answer["resync"] !== true;
144
+ // Replayed in the same epoch, the numbers go on from the page's own;
145
+ // otherwise from the Chest's.
146
+ if (!replayed || since.epoch !== epoch)
147
+ ch.seq = answer["seq"];
148
+ ch.epoch = epoch;
149
+ if (typeof answer["pos"] === "number")
150
+ ch.pos = answer["pos"];
151
+ ch.present = new Map((Array.isArray(answer["presence"]) ? answer["presence"] : []).map(p => [p.id, p.state]));
152
+ if (ch.tracked && member !== undefined)
153
+ ch.present.set(member, ch.tracked);
154
+ if (ch.tracked)
155
+ write({ op: "track", ch: ch.name, state: ch.tracked });
156
+ if (answer["presence"] !== undefined || since !== undefined)
157
+ presenceChanged(ch);
158
+ tellFocus();
159
+ emit(ch.joinedListeners, { replayed });
160
+ if (answer["resync"] === true)
161
+ emit(ch.resyncListeners);
162
+ });
163
+ };
164
+ const receive = (m) => {
165
+ const answer = typeof m["ref"] === "number" ? answers.get(m["ref"]) : undefined;
166
+ if (answer) {
167
+ answers.delete(m["ref"]);
168
+ answer(m);
169
+ return;
170
+ }
171
+ const ch = typeof m["ch"] === "string" ? channels.get(m["ch"]) : undefined;
172
+ switch (m["op"]) {
173
+ case "hello":
174
+ epoch = m["epoch"];
175
+ member = m["member"];
176
+ attempts = 0;
177
+ connected = true;
178
+ focusSent = "";
179
+ clearTimeout(quiet);
180
+ quiet = undefined;
181
+ if (told !== true)
182
+ tell(true);
183
+ pinger = setInterval(() => check(pingWait), pingEvery);
184
+ renewer = setInterval(() => void ask(), renewEvery);
185
+ for (const c of channels.values())
186
+ if (!c.kicked)
187
+ join(c);
188
+ return;
189
+ case "msg":
190
+ if (!ch || !ch.joined)
191
+ return;
192
+ // A feed's row: its position in the tool's change log says whether
193
+ // the page has it already (given again by a replay).
194
+ if (typeof m["pos"] === "number") {
195
+ if (m["pos"] <= ch.pos)
196
+ return;
197
+ ch.pos = m["pos"];
198
+ }
199
+ if (typeof m["seq"] === "number")
200
+ ch.seq = m["seq"];
201
+ fire(ch.listeners, m["event"], m["payload"], { ...(typeof m["pos"] === "number" ? { pos: m["pos"] } : {}), ...(m["partial"] === true ? { partial: true } : {}) });
202
+ return;
203
+ case "peer":
204
+ if (ch?.joined)
205
+ fire(ch.peerListeners, m["event"], m["payload"], m["from"]);
206
+ return;
207
+ case "presence":
208
+ if (!ch)
209
+ return;
210
+ for (const p of m["joins"] ?? [])
211
+ ch.present.set(p.id, p.state);
212
+ for (const id of m["leaves"] ?? [])
213
+ ch.present.delete(id);
214
+ presenceChanged(ch);
215
+ return;
216
+ case "kicked":
217
+ if (!ch)
218
+ return;
219
+ ch.joined = false;
220
+ ch.kicked = true;
221
+ if (focusSent === ch.name)
222
+ focusSent = "";
223
+ emit(ch.kickedListeners);
224
+ return;
225
+ case "direct":
226
+ emit(direct, m["event"], m["payload"]);
227
+ }
228
+ };
229
+ // check pings the Chest: no answer within wait, the connection is dead
230
+ // and another is opened at once.
231
+ const check = (wait) => {
232
+ const s = socket;
233
+ if (!s || !connected)
234
+ return;
235
+ clearTimeout(silence);
236
+ silence = setTimeout(() => lost(s, true), wait);
237
+ write({ op: "ping" }, () => clearTimeout(silence));
238
+ };
239
+ // unwatch stops what runs while connected.
240
+ const unwatch = () => {
241
+ clearInterval(pinger);
242
+ clearInterval(renewer);
243
+ clearTimeout(silence);
244
+ };
245
+ // lost forgets a connection that closed or went silent, tells the page
246
+ // only if no other comes within quietFor, and connects again: at once, or
247
+ // after the backoff.
248
+ const lost = (s, now) => {
249
+ if (socket !== s)
250
+ return;
251
+ socket = undefined;
252
+ connected = false;
253
+ unwatch();
254
+ if (s.readyState <= 1)
255
+ s.close(4000);
256
+ answers.clear();
257
+ for (const c of channels.values()) {
258
+ c.joined = false;
259
+ clearTimeout(c.retry);
260
+ c.retry = undefined;
261
+ }
262
+ if (told === true && quiet === undefined)
263
+ quiet = setTimeout(() => { quiet = undefined; tell(false); }, quietFor);
264
+ reconnect(now ? 0 : backoff());
265
+ };
266
+ // stop stops everything, for good.
267
+ const stop = () => {
268
+ ended = true;
269
+ unwatch();
270
+ clearTimeout(timer);
271
+ clearTimeout(quiet);
272
+ for (const c of channels.values())
273
+ clearTimeout(c.retry);
274
+ if (socket && socket.readyState <= 1)
275
+ socket.close(1000);
276
+ socket = undefined;
277
+ page.removeEventListener?.("online", wake);
278
+ page.removeEventListener?.("offline", gone);
279
+ page.removeEventListener?.("pageshow", restored);
280
+ page.document?.removeEventListener("visibilitychange", visible);
281
+ };
282
+ // end ends for good, and says why.
283
+ const end = (reason) => {
284
+ if (ended)
285
+ return;
286
+ stop();
287
+ emit(closed, reason);
288
+ };
289
+ // delay is the wait before the next attempt, the longer the more failed
290
+ // before it; backoff the wait before connecting again.
291
+ const delay = (failed) => Math.random() * Math.min(lastDelay, firstDelay * 2 ** failed);
292
+ const backoff = () => delay(attempts++);
293
+ // reconnect attempts again after delay (none: at once), unless an
294
+ // attempt is already on its way.
295
+ const reconnect = (delay) => {
296
+ if (ended || socket || asking || timer !== undefined)
297
+ return;
298
+ if (delay === 0)
299
+ return void attempt();
300
+ timer = setTimeout(attempt, delay);
301
+ };
302
+ // attempt asks the Chest before opening: whether the member still may
303
+ // connect, and whether it has room — when full, it waits as long as the
304
+ // Chest asks. Offline, it waits for the network ("online").
305
+ const attempt = async () => {
306
+ timer = undefined;
307
+ if (page.navigator?.onLine === false)
308
+ return;
309
+ asking = true;
310
+ const answer = await ask();
311
+ asking = false;
312
+ if (ended || socket)
313
+ return;
314
+ if (answer?.status === 503)
315
+ return reconnect(Math.max(backoff(), answer.retryAfter * 1000));
316
+ open();
317
+ };
318
+ // ask asks the Chest over HTTPS, without upgrading, whether the member
319
+ // may connect — which renews their session: 401 ends as signed out, 403
320
+ // as access removed, 503 says when there is room again (Retry-After, in
321
+ // seconds). A network down gives no answer.
322
+ const ask = async () => {
323
+ try {
324
+ const answer = await fetch(url.replace(/^ws/u, "http"), { credentials: "same-origin", cache: "no-store" });
325
+ await answer.body?.cancel();
326
+ if (answer.status === 401)
327
+ end("signed_out");
328
+ if (answer.status === 403)
329
+ end("access_removed");
330
+ return { status: answer.status, retryAfter: Number(answer.headers.get("Retry-After")) || 0 };
331
+ }
332
+ catch {
333
+ return undefined;
334
+ }
335
+ };
336
+ const open = () => {
337
+ const s = new WebSocket(url, protocol);
338
+ socket = s;
339
+ s.onmessage = event => {
340
+ let m;
341
+ try {
342
+ m = JSON.parse(String(event.data));
343
+ }
344
+ catch {
345
+ return;
346
+ }
347
+ if (m !== null && typeof m === "object" && !Array.isArray(m))
348
+ receive(m);
349
+ };
350
+ // Every close but access removed is a cut: a session that ended
351
+ // (1008 session_ended) is told by the question before connecting again.
352
+ s.onclose = event => {
353
+ if (socket === s && event.code === 1008 && event.reason === "access_removed")
354
+ return end("access_removed");
355
+ lost(s, false);
356
+ };
357
+ };
358
+ // wake: the page is back — in the foreground, on the network, from the
359
+ // browser's cache. A connection is checked at once; without one, one is
360
+ // opened at once.
361
+ const wake = () => {
362
+ if (ended)
363
+ return;
364
+ if (connected)
365
+ return check(wakeWait);
366
+ if (socket || asking)
367
+ return;
368
+ clearTimeout(timer);
369
+ timer = undefined;
370
+ attempts = 0;
371
+ reconnect(0);
372
+ };
373
+ // gone: the browser says the network is gone — a Wi-Fi left, a cable
374
+ // pulled —: the connection is dropped at once, and the page waits for it
375
+ // to come back ("online") rather than for a ping to go unanswered.
376
+ const gone = () => { if (!ended && socket)
377
+ lost(socket, false); };
378
+ // visibilitychange: shown, the page wakes; shown or hidden, the Chest is
379
+ // told what it has on screen.
380
+ const visible = () => {
381
+ if (shown())
382
+ wake();
383
+ tellFocus();
384
+ };
385
+ const restored = (event) => { if (event.persisted)
386
+ wake(); };
387
+ page.addEventListener?.("online", wake);
388
+ page.addEventListener?.("offline", gone);
389
+ page.addEventListener?.("pageshow", restored);
390
+ page.document?.addEventListener("visibilitychange", visible);
391
+ open();
392
+ return {
393
+ get member() { return member; },
394
+ channel(name) {
395
+ let ch = channels.get(name);
396
+ if (!ch) {
397
+ ch = { name, listeners: new Map(), peerListeners: new Map(), joinedListeners: new Set(), resyncListeners: new Set(), kickedListeners: new Set(), refusedListeners: new Set(), presenceListeners: new Set(), present: new Map(), epoch: undefined, seq: 0, pos: 0, joined: false, kicked: false, full: 0, retry: undefined };
398
+ channels.set(name, ch);
399
+ if (connected)
400
+ join(ch);
401
+ }
402
+ const state = ch;
403
+ return {
404
+ on: (event, listener) => listenTo(state.listeners, event, listener),
405
+ onJoined: listener => listen(state.joinedListeners, listener),
406
+ onResync: listener => listen(state.resyncListeners, listener),
407
+ onKicked: listener => listen(state.kickedListeners, listener),
408
+ onRefused: listener => listen(state.refusedListeners, listener),
409
+ peers: {
410
+ on: (event, listener) => listenTo(state.peerListeners, event, listener),
411
+ send(event, payload) {
412
+ if (typeof event !== "string" || !peerEventPattern.test(event))
413
+ throw new TypeError("invalid_event: a member's message is 1 to 64 of a-z 0-9 _ -, without a dot");
414
+ if (state.joined)
415
+ write({ op: "send", ch: state.name, event, payload: payload ?? null });
416
+ },
417
+ },
418
+ presence: {
419
+ track(value) {
420
+ state.tracked = value;
421
+ if (member !== undefined) {
422
+ state.present.set(member, value);
423
+ presenceChanged(state);
424
+ }
425
+ if (state.joined)
426
+ write({ op: "track", ch: state.name, state: value });
427
+ },
428
+ list: () => [...state.present].map(([id, value]) => ({ id, state: value })),
429
+ on: listener => listen(state.presenceListeners, listener),
430
+ },
431
+ // leave leaves the channel: the Chest forgets the page's focus on it.
432
+ leave() {
433
+ channels.delete(state.name);
434
+ clearTimeout(state.retry);
435
+ if (state.joined)
436
+ write({ op: "leave", ch: state.name });
437
+ state.joined = false;
438
+ if (focusSent === state.name)
439
+ focusSent = "";
440
+ },
441
+ };
442
+ },
443
+ focus(name) {
444
+ focused = name;
445
+ tellFocus();
446
+ },
447
+ on(event, listener) {
448
+ return listen((event === "direct" ? direct : event === "status" ? status : closed), listener);
449
+ },
450
+ close: stop,
451
+ };
452
+ }
453
+ //# sourceMappingURL=realtime-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-client.js","sourceRoot":"","sources":["../../client/src/realtime-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export type Present = {
2
+ id: string;
3
+ state: Record<string, unknown>;
4
+ };
5
+ export declare const channelPattern: RegExp;
6
+ export declare const eventPattern: RegExp;
7
+ export declare function publish(channel: string, event: string, payload?: unknown): Promise<{
8
+ seq: number;
9
+ }>;
10
+ export declare function send(memberIds: Iterable<string>, event: string, payload?: unknown): Promise<{
11
+ reached: string[];
12
+ }>;
13
+ export declare function online(memberIds: Iterable<string>, options?: {
14
+ channel?: string;
15
+ }): Promise<{
16
+ online: string[];
17
+ watching: string[];
18
+ }>;
19
+ export declare function presence(channel: string): Promise<{
20
+ members: Present[];
21
+ }>;
22
+ //# sourceMappingURL=realtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../client/src/realtime.ts"],"names":[],"mappings":"AA0BA,MAAM,MAAM,OAAO,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC;AAIrE,eAAO,MAAM,cAAc,QAA8C,CAAC;AAC1E,eAAO,MAAM,YAAY,QAAyB,CAAC;AAgDnD,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAIzG;AAID,wBAAsB,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAGxH;AAOD,wBAAsB,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAK/I;AAID,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,EAAE,CAAA;CAAE,CAAC,CAW/E"}
@@ -0,0 +1,99 @@
1
+ import { ask as chest, json, refusal } from "./api.js";
2
+ import { ChestError, TooLarge, Unavailable } from "./errors.js";
3
+ import { memberIdPattern } from "./member.js";
4
+ // The grammars of the Chest: a channel is segments of a-z 0-9 _ - joined by
5
+ // colons, 128 characters at most; an event 1 to 64 of a-z 0-9 . _ -.
6
+ export const channelPattern = /^[a-z0-9_-]{1,64}(?::[a-z0-9_-]{1,64})*$/u;
7
+ export const eventPattern = /^[a-z0-9._-]{1,64}$/u;
8
+ const maxChannel = 128, maxPayload = 64 << 10;
9
+ function checkChannel(channel) {
10
+ if (typeof channel !== "string" || channel.length > maxChannel || !channelPattern.test(channel))
11
+ throw new ChestError("invalid_channel", 400, "a channel is segments of a-z 0-9 _ - joined by colons");
12
+ return channel;
13
+ }
14
+ function checkEvent(event) {
15
+ if (typeof event !== "string" || !eventPattern.test(event))
16
+ throw new ChestError("invalid_event", 400, "an event is 1 to 64 of a-z 0-9 . _ -");
17
+ return event;
18
+ }
19
+ function checkIds(ids) {
20
+ const all = [...ids];
21
+ if (all.length < 1)
22
+ throw new ChestError("invalid_body", 400, "one member identifier at least");
23
+ if (!all.every(id => typeof id === "string" && memberIdPattern.test(id)))
24
+ throw new ChestError("invalid_id", 400, "invalid member identifier");
25
+ return all;
26
+ }
27
+ // body is a call's JSON; a payload the Chest would refuse is refused here.
28
+ function body(fields) {
29
+ const payload = JSON.stringify(fields["payload"] ?? null);
30
+ if (payload === undefined)
31
+ throw new ChestError("invalid_body", 400, "a payload is JSON");
32
+ if (Buffer.byteLength(payload) > maxPayload)
33
+ throw new TooLarge();
34
+ return JSON.stringify(fields);
35
+ }
36
+ const call = async (method, path, value) => {
37
+ const response = await chest("realtime", method, path, value === undefined ? {} : { body: value, type: "application/json" });
38
+ if (response.status !== 200) {
39
+ if (response.status < 400) {
40
+ await response.body?.cancel();
41
+ throw new Unavailable();
42
+ }
43
+ throw await refusal(response, "realtime");
44
+ }
45
+ return json(response);
46
+ };
47
+ const record = (v) => {
48
+ if (v === null || typeof v !== "object" || Array.isArray(v))
49
+ throw new Unavailable();
50
+ return v;
51
+ };
52
+ const ids = (v) => {
53
+ if (!Array.isArray(v) || !v.every(id => typeof id === "string" && memberIdPattern.test(id)))
54
+ throw new Unavailable();
55
+ return [...v];
56
+ };
57
+ // publish delivers an event to every page joined to a channel the tool
58
+ // declares — numbered, in order, kept a short while for a page that
59
+ // reconnects —: its number in the channel.
60
+ export async function publish(channel, event, payload) {
61
+ const answer = record(await call("POST", "/realtime/publish", body({ channel: checkChannel(channel), event: checkEvent(event), payload })));
62
+ if (!Number.isSafeInteger(answer["seq"]) || answer["seq"] < 1)
63
+ throw new Unavailable();
64
+ return { seq: answer["seq"] };
65
+ }
66
+ // send delivers an event to every page of these members, outside any
67
+ // channel: those it reached. The others are not online in the tool.
68
+ export async function send(memberIds, event, payload) {
69
+ const answer = record(await call("POST", "/realtime/send", body({ members: checkIds(memberIds), event: checkEvent(event), payload })));
70
+ return { reached: ids(answer["reached"]) };
71
+ }
72
+ // online says which of these members have a page of the tool open now,
73
+ // and, given a channel, which of them watch it — a page focused on it
74
+ // (live.focus) and in the foreground: what decides whom to notify. A chat
75
+ // notifies the members online but not watching the conversation, and every
76
+ // member not online: those watching it see the message already.
77
+ export async function online(memberIds, options = {}) {
78
+ const members = checkIds(memberIds);
79
+ const channel = options.channel === undefined ? undefined : checkChannel(options.channel);
80
+ const answer = record(await call("POST", "/realtime/online", JSON.stringify({ members, ...(channel === undefined ? {} : { channel }) })));
81
+ return { online: ids(answer["online"]), watching: ids(answer["watching"]) };
82
+ }
83
+ // presence is who appears in a channel now — merged across their pages —,
84
+ // with the state they track.
85
+ export async function presence(channel) {
86
+ const answer = record(await call("GET", "/realtime/presence?channel=" + encodeURIComponent(checkChannel(channel))));
87
+ const members = answer["members"];
88
+ if (!Array.isArray(members))
89
+ throw new Unavailable();
90
+ return {
91
+ members: members.map(m => {
92
+ const p = record(m);
93
+ if (typeof p["id"] !== "string" || !memberIdPattern.test(p["id"]))
94
+ throw new Unavailable();
95
+ return { id: p["id"], state: record(p["state"]) };
96
+ }),
97
+ };
98
+ }
99
+ //# sourceMappingURL=realtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime.js","sourceRoot":"","sources":["../../client/src/realtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { IncomingMessage } from "node:http";
2
+ export type SealOptions = {
3
+ roles?: string[];
4
+ context?: string;
5
+ };
6
+ export type SealItem = {
7
+ value: string;
8
+ } & SealOptions;
9
+ export type OpenItem = {
10
+ sealed: string;
11
+ context?: string;
12
+ };
13
+ export declare function isSealed(text: unknown): text is string;
14
+ export declare function sealMany(items: SealItem[]): Promise<string[]>;
15
+ export declare function seal(value: string, options?: SealOptions): Promise<string>;
16
+ export declare function openMany(request: IncomingMessage | Request, items: OpenItem[]): Promise<(string | null)[]>;
17
+ export declare function open(request: IncomingMessage | Request, sealed: string, options?: {
18
+ context?: string;
19
+ }): Promise<string>;
20
+ //# sourceMappingURL=sealed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sealed.d.ts","sourceRoot":"","sources":["../../client/src/sealed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AA2CjD,MAAM,MAAM,WAAW,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE,MAAM,MAAM,QAAQ,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,WAAW,CAAC;AACvD,MAAM,MAAM,QAAQ,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAa5D,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,MAAM,CAEtD;AAgDD,wBAAsB,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAKnE;AAGD,wBAAsB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAEpF;AAKD,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAiBhH;AAKD,wBAAsB,IAAI,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAWlI"}