@procedures/client 0.48.0 → 0.48.1
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 +8 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/browser.d.ts +2 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +2 -0
- package/dist/browser.js.map +1 -1
- package/dist/events/index.d.ts +4 -0
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +3 -0
- package/dist/events/index.js.map +1 -1
- package/dist/events/live-state.d.ts +289 -0
- package/dist/events/live-state.d.ts.map +1 -0
- package/dist/events/live-state.js +501 -0
- package/dist/events/live-state.js.map +1 -0
- package/dist/events/live-view.d.ts +38 -0
- package/dist/events/live-view.d.ts.map +1 -0
- package/dist/events/live-view.js +109 -0
- package/dist/events/live-view.js.map +1 -0
- package/dist/events/publisher.d.ts +18 -1
- package/dist/events/publisher.d.ts.map +1 -1
- package/dist/events/publisher.js +23 -1
- package/dist/events/publisher.js.map +1 -1
- package/dist/server/procedure-server.d.ts.map +1 -1
- package/dist/server/procedure-server.js +3 -0
- package/dist/server/procedure-server.js.map +1 -1
- package/package.json +1 -1
- package/src/browser.ts +19 -0
- package/src/events/index.ts +29 -0
- package/src/events/live-state.ts +666 -0
- package/src/events/live-view.ts +134 -0
- package/src/events/publisher.ts +31 -1
- package/src/server/procedure-server.ts +2 -0
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The live state of a topic (documentation/LIVE-STATE-2026-11.md).
|
|
3
|
+
*
|
|
4
|
+
* Some state changes many times a second, and each reader needs only its latest value: who is here,
|
|
5
|
+
* and where a cursor is. This state keeps the latest value of each key of a topic in memory. It
|
|
6
|
+
* makes no store write and no numbered change.
|
|
7
|
+
*
|
|
8
|
+
* - A set keeps the value and publishes it to the subscribers of the topic, through the bus. The
|
|
9
|
+
* first change on an idle topic goes at once and opens a window. One event at the end of the
|
|
10
|
+
* window carries each key that changed in it, and that event opens the next window.
|
|
11
|
+
* - A snapshot gives the live values, so a new reader sees them at once.
|
|
12
|
+
* - A key ends after a stated time with no set, when the connection of its owner closes, and at a
|
|
13
|
+
* leave call. Each end publishes a `gone` item.
|
|
14
|
+
*
|
|
15
|
+
* The state fills from the bus too. A bus that hosts share thus shares the state. A snapshot holds
|
|
16
|
+
* only what this host saw.
|
|
17
|
+
*/
|
|
18
|
+
import * as z from "zod";
|
|
19
|
+
import { createProcedure } from "../procedures/define.js";
|
|
20
|
+
import { InvocationError } from "../procedures/invoke.js";
|
|
21
|
+
import { decodeSegment, encodeSegment } from "../procedures/segments.js";
|
|
22
|
+
import { ms, toMs } from "../duration.js";
|
|
23
|
+
import { realClock } from "../clock.js";
|
|
24
|
+
/** The path of the procedure that sets a key of a live topic. */
|
|
25
|
+
export const LIVE_SET_PATH = ["live", "set"];
|
|
26
|
+
/** The path of the procedure that gives the live values of a topic. */
|
|
27
|
+
export const LIVE_SNAPSHOT_PATH = ["live", "snapshot"];
|
|
28
|
+
/** The path of the procedure that ends a key of a live topic. */
|
|
29
|
+
export const LIVE_LEAVE_PATH = ["live", "leave"];
|
|
30
|
+
/** The longest key of a live topic, in characters. */
|
|
31
|
+
export const MAX_LIVE_KEY_LENGTH = 256;
|
|
32
|
+
/** The default limit of the keys of one live topic. */
|
|
33
|
+
export const DEFAULT_LIVE_KEYS = 1024;
|
|
34
|
+
/** The default limit of the bytes of one value, as JSON. */
|
|
35
|
+
export const DEFAULT_LIVE_VALUE_BYTES = 16384;
|
|
36
|
+
/** The default limit of the topics of one live state. */
|
|
37
|
+
export const DEFAULT_LIVE_TOPICS = 4096;
|
|
38
|
+
/** The prefix of each live topic. */
|
|
39
|
+
const PREFIX = "live.";
|
|
40
|
+
/** The default window that joins the sets of a topic, in milliseconds. */
|
|
41
|
+
const DEFAULT_WINDOW_MS = 120;
|
|
42
|
+
/**
|
|
43
|
+
* This function gives a live topic: `live.<name>`, or `live.<name>.<partition>`. The name encodes
|
|
44
|
+
* `%` and `.`, so the first dot after the name ends the name, as in a topic of a collection.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* liveTopic("presence"); // "live.presence"
|
|
49
|
+
* liveTopic("presence", "acme/board:b1"); // "live.presence.acme/board:b1"
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export function liveTopic(name, partition) {
|
|
53
|
+
const topic = `${PREFIX}${encodeSegment(name)}`;
|
|
54
|
+
return partition === undefined ? topic : `${topic}.${partition}`;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* This function gives the name and the partition of a live topic, or undefined for another topic.
|
|
58
|
+
* Only the canonical form counts: `liveTopic()` gives the same topic back.
|
|
59
|
+
*/
|
|
60
|
+
export function liveTopicTarget(topic) {
|
|
61
|
+
if (!topic.startsWith(PREFIX))
|
|
62
|
+
return undefined;
|
|
63
|
+
const rest = topic.slice(PREFIX.length);
|
|
64
|
+
const dot = rest.indexOf(".");
|
|
65
|
+
const name = decodeSegment(dot === -1 ? rest : rest.slice(0, dot));
|
|
66
|
+
if (name.length === 0)
|
|
67
|
+
return undefined;
|
|
68
|
+
if (dot === -1)
|
|
69
|
+
return liveTopic(name) === topic ? { name } : undefined;
|
|
70
|
+
const partition = rest.slice(dot + 1);
|
|
71
|
+
if (partition.length === 0)
|
|
72
|
+
return undefined;
|
|
73
|
+
return liveTopic(name, partition) === topic ? { name, partition } : undefined;
|
|
74
|
+
}
|
|
75
|
+
/** True for a value of the form of a live event. */
|
|
76
|
+
function isLiveEvent(value) {
|
|
77
|
+
if (typeof value !== "object" || value === null)
|
|
78
|
+
return false;
|
|
79
|
+
const event = value;
|
|
80
|
+
return typeof event.origin === "string" && Array.isArray(event.set) && Array.isArray(event.gone);
|
|
81
|
+
}
|
|
82
|
+
/** This function gives a refusal of a set. */
|
|
83
|
+
function refused(message, reason, path = LIVE_SET_PATH) {
|
|
84
|
+
return new InvocationError("FORBIDDEN", message, [...path], reason);
|
|
85
|
+
}
|
|
86
|
+
/** This function gives a new id for a live state. */
|
|
87
|
+
function newOrigin() {
|
|
88
|
+
const random = globalThis.crypto?.randomUUID;
|
|
89
|
+
return random ? random.call(globalThis.crypto) : `live-${Date.now()}-${Math.random()}`;
|
|
90
|
+
}
|
|
91
|
+
const entrySchema = z.object({
|
|
92
|
+
key: z.string(),
|
|
93
|
+
value: z.unknown(),
|
|
94
|
+
by: z.string().optional(),
|
|
95
|
+
at: z.number(),
|
|
96
|
+
});
|
|
97
|
+
/**
|
|
98
|
+
* The live values of the topics of one publisher. A host gets one with the option `live` of
|
|
99
|
+
* `EventPublisher`, and the server registers its `procedures`.
|
|
100
|
+
*/
|
|
101
|
+
export class LiveState {
|
|
102
|
+
/** The procedures `live.set`, `live.snapshot` and `live.leave`. The expose rule of the host applies to them. */
|
|
103
|
+
procedures;
|
|
104
|
+
bus;
|
|
105
|
+
clock;
|
|
106
|
+
admit;
|
|
107
|
+
admitSet;
|
|
108
|
+
admitLeave;
|
|
109
|
+
partition;
|
|
110
|
+
expiresMs;
|
|
111
|
+
windowOf;
|
|
112
|
+
maxKeys;
|
|
113
|
+
maxValueBytes;
|
|
114
|
+
maxTopics;
|
|
115
|
+
origin = newOrigin();
|
|
116
|
+
topics = new Map();
|
|
117
|
+
/** Each key in the order of its last set. All keys have the same time, so this is the order of the deadlines. */
|
|
118
|
+
deadlines = new Set();
|
|
119
|
+
owned = new Map();
|
|
120
|
+
timer;
|
|
121
|
+
closed = false;
|
|
122
|
+
constructor(options, host) {
|
|
123
|
+
if (typeof options.admitSet !== "function")
|
|
124
|
+
throw new TypeError("LiveState needs the option admitSet");
|
|
125
|
+
this.bus = host.bus;
|
|
126
|
+
this.clock = options.clock ?? host.clock ?? realClock;
|
|
127
|
+
this.admit = host.admit;
|
|
128
|
+
this.admitSet = options.admitSet;
|
|
129
|
+
this.admitLeave = options.admitLeave;
|
|
130
|
+
this.partition = options.partition;
|
|
131
|
+
this.expiresMs = toMs(options.expiresAfter, "expiresAfter");
|
|
132
|
+
if (this.expiresMs <= 0)
|
|
133
|
+
throw new RangeError("expiresAfter must be more than 0");
|
|
134
|
+
const window = options.window ?? ms(DEFAULT_WINDOW_MS);
|
|
135
|
+
this.windowOf = typeof window === "function" ? window : () => window;
|
|
136
|
+
this.maxKeys = options.maxKeysPerTopic ?? DEFAULT_LIVE_KEYS;
|
|
137
|
+
this.maxValueBytes = options.maxValueBytes ?? DEFAULT_LIVE_VALUE_BYTES;
|
|
138
|
+
this.maxTopics = options.maxTopics ?? DEFAULT_LIVE_TOPICS;
|
|
139
|
+
this.procedures = [this.setProcedure(host.topicSchema), this.snapshotProcedure(host.topicSchema), this.leaveProcedure(host.topicSchema)];
|
|
140
|
+
}
|
|
141
|
+
/** The number of live keys of this state. */
|
|
142
|
+
get size() {
|
|
143
|
+
return this.deadlines.size;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* The topic of the bus for a live topic of a call, or undefined for another topic. The publisher
|
|
147
|
+
* calls it for each subscription and each re-check, so a change of the partition ends a
|
|
148
|
+
* subscription.
|
|
149
|
+
*/
|
|
150
|
+
async route(topic, ctx) {
|
|
151
|
+
const target = liveTopicTarget(topic);
|
|
152
|
+
if (!target)
|
|
153
|
+
return undefined;
|
|
154
|
+
if (!this.partition) {
|
|
155
|
+
if (target.partition !== undefined)
|
|
156
|
+
throw refused(`The live topic "${topic}" has no partitions`, "partition-not-allowed");
|
|
157
|
+
return topic;
|
|
158
|
+
}
|
|
159
|
+
const partition = await this.partition(ctx, target.partition);
|
|
160
|
+
if (partition === null)
|
|
161
|
+
throw refused(`The call cannot use the partition of the live topic "${topic}"`, "partition-not-allowed");
|
|
162
|
+
return liveTopic(target.name, partition);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* This method keeps the latest value of a key and publishes it. This is the direct form for the
|
|
166
|
+
* host: it runs no check of a right, and `topic` is a topic of the bus.
|
|
167
|
+
*
|
|
168
|
+
* @returns The time of the set on the clock
|
|
169
|
+
* @throws `InvocationError` with the code `FORBIDDEN` at a limit, and the existing values stay
|
|
170
|
+
*/
|
|
171
|
+
set(topic, key, value, options = {}) {
|
|
172
|
+
if (this.closed)
|
|
173
|
+
throw refused("The live state is closed", "write-not-allowed");
|
|
174
|
+
this.checkValue(value);
|
|
175
|
+
const state = this.stateOf(topic);
|
|
176
|
+
if (!state)
|
|
177
|
+
throw refused(`The live state has its limit of ${this.maxTopics} topics`, "write-not-allowed");
|
|
178
|
+
const at = this.clock.now();
|
|
179
|
+
const entry = options.by === undefined ? { key, value, at } : { key, value, by: options.by, at };
|
|
180
|
+
let slot = state.keys.get(key);
|
|
181
|
+
if (slot) {
|
|
182
|
+
slot.entry = entry;
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
if (state.keys.size >= this.maxKeys)
|
|
186
|
+
throw refused(`The live topic "${topic}" has its limit of ${this.maxKeys} keys`, "write-not-allowed");
|
|
187
|
+
slot = { state, key, entry, deadline: 0, owner: undefined };
|
|
188
|
+
state.keys.set(key, slot);
|
|
189
|
+
}
|
|
190
|
+
this.renew(slot, at);
|
|
191
|
+
this.own(slot, options.owner);
|
|
192
|
+
this.queue(state, (waiting) => {
|
|
193
|
+
waiting.gone.delete(key);
|
|
194
|
+
waiting.set.set(key, entry);
|
|
195
|
+
});
|
|
196
|
+
return at;
|
|
197
|
+
}
|
|
198
|
+
/** This method gives the live values of a topic of the bus. */
|
|
199
|
+
snapshot(topic) {
|
|
200
|
+
if (this.closed)
|
|
201
|
+
return [];
|
|
202
|
+
const state = this.stateOf(topic);
|
|
203
|
+
return state ? Array.from(state.keys.values(), (slot) => slot.entry) : [];
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* This method ends a key and publishes the end with the reason `left`. This is the direct form for
|
|
207
|
+
* the host: it runs no check of a right, and `topic` is a topic of the bus.
|
|
208
|
+
*
|
|
209
|
+
* @returns True when the key was live
|
|
210
|
+
*/
|
|
211
|
+
leave(topic, key) {
|
|
212
|
+
const slot = this.topics.get(topic)?.keys.get(key);
|
|
213
|
+
if (this.closed || !slot)
|
|
214
|
+
return false;
|
|
215
|
+
this.end(slot, "left", true);
|
|
216
|
+
return true;
|
|
217
|
+
}
|
|
218
|
+
/** This method ends each key that the connection owns. The transport of the host calls it at a close. */
|
|
219
|
+
connectionClosed(connection) {
|
|
220
|
+
const slots = this.owned.get(connection);
|
|
221
|
+
if (!slots)
|
|
222
|
+
return;
|
|
223
|
+
this.owned.delete(connection);
|
|
224
|
+
for (const slot of slots) {
|
|
225
|
+
slot.owner = undefined;
|
|
226
|
+
this.end(slot, "closed", true);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/** This method stops the timers and the listeners. The state then holds nothing. */
|
|
230
|
+
close() {
|
|
231
|
+
if (this.closed)
|
|
232
|
+
return;
|
|
233
|
+
this.closed = true;
|
|
234
|
+
this.timer?.();
|
|
235
|
+
this.timer = undefined;
|
|
236
|
+
for (const state of this.topics.values()) {
|
|
237
|
+
state.window?.();
|
|
238
|
+
state.stop();
|
|
239
|
+
}
|
|
240
|
+
this.topics.clear();
|
|
241
|
+
this.deadlines.clear();
|
|
242
|
+
this.owned.clear();
|
|
243
|
+
}
|
|
244
|
+
/** This method refuses a value above the limit. A text has at most 3 bytes for each UTF-16 unit. */
|
|
245
|
+
checkValue(value) {
|
|
246
|
+
const text = JSON.stringify(value);
|
|
247
|
+
if (text === undefined)
|
|
248
|
+
throw refused("A live value must have a JSON form", "write-not-allowed");
|
|
249
|
+
const fits = text.length * 3 <= this.maxValueBytes
|
|
250
|
+
|| (text.length <= this.maxValueBytes && new TextEncoder().encode(text).length <= this.maxValueBytes);
|
|
251
|
+
if (!fits)
|
|
252
|
+
throw refused(`A live value has more than ${this.maxValueBytes} bytes`, "write-not-allowed");
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* The state of a topic. The first use starts the listener of the bus. A topic stays after its
|
|
256
|
+
* last key, and goes when a new topic needs its place. Undefined means that no place is free.
|
|
257
|
+
*/
|
|
258
|
+
stateOf(topic) {
|
|
259
|
+
const known = this.topics.get(topic);
|
|
260
|
+
if (known)
|
|
261
|
+
return known;
|
|
262
|
+
if (this.topics.size >= this.maxTopics) {
|
|
263
|
+
for (const state of this.topics.values()) {
|
|
264
|
+
if (state.keys.size === 0 && !state.window) {
|
|
265
|
+
state.stop();
|
|
266
|
+
this.topics.delete(state.topic);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (this.topics.size >= this.maxTopics)
|
|
270
|
+
return undefined;
|
|
271
|
+
}
|
|
272
|
+
const stop = this.bus.on(topic, (event) => this.heard(topic, event));
|
|
273
|
+
const state = { topic, keys: new Map(), stop, windowMs: toMs(this.windowOf(topic), "window"), waiting: undefined, window: undefined };
|
|
274
|
+
this.topics.set(topic, state);
|
|
275
|
+
return state;
|
|
276
|
+
}
|
|
277
|
+
/** This method applies an event of another host. Its subscribers on this host got it from the bus. */
|
|
278
|
+
heard(topic, event) {
|
|
279
|
+
if (this.closed || !isLiveEvent(event) || event.origin === this.origin)
|
|
280
|
+
return;
|
|
281
|
+
const state = this.topics.get(topic);
|
|
282
|
+
if (!state)
|
|
283
|
+
return;
|
|
284
|
+
const now = this.clock.now();
|
|
285
|
+
for (const entry of event.set) {
|
|
286
|
+
let slot = state.keys.get(entry.key);
|
|
287
|
+
if (slot) {
|
|
288
|
+
slot.entry = entry;
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
if (state.keys.size >= this.maxKeys)
|
|
292
|
+
continue;
|
|
293
|
+
slot = { state, key: entry.key, entry, deadline: 0, owner: undefined };
|
|
294
|
+
state.keys.set(entry.key, slot);
|
|
295
|
+
}
|
|
296
|
+
// The connection of this key is on the other host: its deadline ends the key if that host dies
|
|
297
|
+
this.own(slot, undefined);
|
|
298
|
+
this.renew(slot, now);
|
|
299
|
+
}
|
|
300
|
+
for (const { key, reason } of event.gone) {
|
|
301
|
+
const slot = state.keys.get(key);
|
|
302
|
+
if (slot)
|
|
303
|
+
this.end(slot, reason, false);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/** This method moves a key to the end of the deadlines. */
|
|
307
|
+
renew(slot, now) {
|
|
308
|
+
slot.deadline = now + this.expiresMs;
|
|
309
|
+
this.deadlines.delete(slot);
|
|
310
|
+
this.deadlines.add(slot);
|
|
311
|
+
this.armDeadline();
|
|
312
|
+
}
|
|
313
|
+
/** This method sets the owner of a key. The owner is the connection of the last set. */
|
|
314
|
+
own(slot, owner) {
|
|
315
|
+
if (slot.owner === owner)
|
|
316
|
+
return;
|
|
317
|
+
if (slot.owner !== undefined) {
|
|
318
|
+
const slots = this.owned.get(slot.owner);
|
|
319
|
+
slots?.delete(slot);
|
|
320
|
+
if (slots?.size === 0)
|
|
321
|
+
this.owned.delete(slot.owner);
|
|
322
|
+
}
|
|
323
|
+
slot.owner = owner;
|
|
324
|
+
if (owner === undefined)
|
|
325
|
+
return;
|
|
326
|
+
const slots = this.owned.get(owner);
|
|
327
|
+
if (slots)
|
|
328
|
+
slots.add(slot);
|
|
329
|
+
else
|
|
330
|
+
this.owned.set(owner, new Set([slot]));
|
|
331
|
+
}
|
|
332
|
+
/** This method removes a key, and publishes its end when this host decided it. */
|
|
333
|
+
end(slot, reason, publish) {
|
|
334
|
+
this.own(slot, undefined);
|
|
335
|
+
this.deadlines.delete(slot);
|
|
336
|
+
slot.state.keys.delete(slot.key);
|
|
337
|
+
if (!publish)
|
|
338
|
+
return;
|
|
339
|
+
this.queue(slot.state, (waiting) => {
|
|
340
|
+
waiting.set.delete(slot.key);
|
|
341
|
+
waiting.gone.set(slot.key, { key: slot.key, reason });
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
/** This method starts the one timer of the deadlines, at the first deadline. */
|
|
345
|
+
armDeadline() {
|
|
346
|
+
if (this.timer || this.closed)
|
|
347
|
+
return;
|
|
348
|
+
const first = this.deadlines.values().next();
|
|
349
|
+
if (first.done)
|
|
350
|
+
return;
|
|
351
|
+
const timer = this.clock.after(Math.max(0, first.value.deadline - this.clock.now()), () => {
|
|
352
|
+
this.timer = undefined;
|
|
353
|
+
this.expire();
|
|
354
|
+
});
|
|
355
|
+
// A deadline does not keep a Node process alive
|
|
356
|
+
timer.unref?.();
|
|
357
|
+
this.timer = timer;
|
|
358
|
+
}
|
|
359
|
+
/** This method ends each key at its deadline. */
|
|
360
|
+
expire() {
|
|
361
|
+
const now = this.clock.now();
|
|
362
|
+
for (const slot of this.deadlines) {
|
|
363
|
+
if (slot.deadline > now)
|
|
364
|
+
break;
|
|
365
|
+
this.end(slot, "expired", true);
|
|
366
|
+
}
|
|
367
|
+
this.armDeadline();
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* This method adds a change to a topic. On an idle topic the change goes at once, so one writer
|
|
371
|
+
* has no added delay, and the window opens. In an open window the change waits, and the latest
|
|
372
|
+
* change of a key wins.
|
|
373
|
+
*/
|
|
374
|
+
queue(state, change) {
|
|
375
|
+
let waiting = state.waiting;
|
|
376
|
+
if (!waiting) {
|
|
377
|
+
waiting = { set: new Map(), gone: new Map() };
|
|
378
|
+
state.waiting = waiting;
|
|
379
|
+
}
|
|
380
|
+
change(waiting);
|
|
381
|
+
if (!state.window)
|
|
382
|
+
this.publishWaiting(state);
|
|
383
|
+
}
|
|
384
|
+
/** This method publishes the changes that wait as one event, and opens the next window. */
|
|
385
|
+
publishWaiting(state) {
|
|
386
|
+
const waiting = state.waiting;
|
|
387
|
+
if (!waiting || this.closed)
|
|
388
|
+
return;
|
|
389
|
+
state.waiting = undefined;
|
|
390
|
+
if (state.windowMs > 0) {
|
|
391
|
+
const timer = this.clock.after(state.windowMs, () => {
|
|
392
|
+
state.window = undefined;
|
|
393
|
+
this.publishWaiting(state);
|
|
394
|
+
});
|
|
395
|
+
timer.unref?.();
|
|
396
|
+
state.window = timer;
|
|
397
|
+
}
|
|
398
|
+
const event = { origin: this.origin, set: [...waiting.set.values()], gone: [...waiting.gone.values()] };
|
|
399
|
+
this.bus.emit(state.topic, event);
|
|
400
|
+
}
|
|
401
|
+
/** The procedure `live.set`: the checks of a subscription, then `admitSet`, then the set. */
|
|
402
|
+
setProcedure(topicSchema) {
|
|
403
|
+
return createProcedure()
|
|
404
|
+
.path([...LIVE_SET_PATH])
|
|
405
|
+
.input(z.object({
|
|
406
|
+
topic: topicSchema,
|
|
407
|
+
key: z.string().min(1).max(MAX_LIVE_KEY_LENGTH).describe("The key of the value"),
|
|
408
|
+
value: z.unknown().refine((value) => value !== undefined, "A live set needs a value").describe("The latest value of the key"),
|
|
409
|
+
}))
|
|
410
|
+
.output(z.object({ at: z.number().describe("The time of the set on the clock of the host") }))
|
|
411
|
+
.meta({
|
|
412
|
+
description: "This procedure keeps the latest value of a key of a live topic and publishes it. It makes no store write.",
|
|
413
|
+
effects: { reads: ["events"], writes: ["live"] },
|
|
414
|
+
})
|
|
415
|
+
.handler(async (input, ctx) => {
|
|
416
|
+
const topic = await this.admit(input.topic, ctx);
|
|
417
|
+
if (!liveTopicTarget(topic))
|
|
418
|
+
throw refused(`The topic "${input.topic}" is not a live topic`, "write-not-allowed");
|
|
419
|
+
const admission = await this.admitSet({
|
|
420
|
+
topic,
|
|
421
|
+
key: input.key,
|
|
422
|
+
value: input.value,
|
|
423
|
+
capability: ctx.capability,
|
|
424
|
+
metadata: ctx.metadata,
|
|
425
|
+
...(ctx.principal ? { principal: ctx.principal } : {}),
|
|
426
|
+
});
|
|
427
|
+
if (admission === null)
|
|
428
|
+
throw refused(`The call cannot set a key of the live topic "${input.topic}"`, "write-not-allowed");
|
|
429
|
+
const connection = ctx.metadata["connectionId"];
|
|
430
|
+
const owner = typeof connection === "string" ? connection : undefined;
|
|
431
|
+
// A connection that closed during the checks owns no new key
|
|
432
|
+
if (ctx.signal?.aborted)
|
|
433
|
+
throw refused("The call ended before the set", "write-not-allowed");
|
|
434
|
+
const value = admission.value !== undefined ? admission.value : input.value;
|
|
435
|
+
return { at: this.set(topic, input.key, value, { by: admission.by, owner }) };
|
|
436
|
+
})
|
|
437
|
+
.build();
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* The procedure `live.leave`: the checks of a subscription, then the right to end the key. A set
|
|
441
|
+
* that comes during the check of the right keeps the key, because the check read the older set.
|
|
442
|
+
*/
|
|
443
|
+
leaveProcedure(topicSchema) {
|
|
444
|
+
return createProcedure()
|
|
445
|
+
.path([...LIVE_LEAVE_PATH])
|
|
446
|
+
.input(z.object({
|
|
447
|
+
topic: topicSchema,
|
|
448
|
+
key: z.string().min(1).max(MAX_LIVE_KEY_LENGTH).describe("The key to end"),
|
|
449
|
+
}))
|
|
450
|
+
.output(z.object({ ended: z.boolean().describe("True when the call ended a live key") }))
|
|
451
|
+
.meta({
|
|
452
|
+
description: "This procedure ends a key of a live topic. Each reader gets the end at once, or at the end of an open window.",
|
|
453
|
+
effects: { reads: ["events"], writes: ["live"] },
|
|
454
|
+
})
|
|
455
|
+
.handler(async (input, ctx) => {
|
|
456
|
+
const topic = await this.admit(input.topic, ctx);
|
|
457
|
+
if (!liveTopicTarget(topic))
|
|
458
|
+
throw refused(`The topic "${input.topic}" is not a live topic`, "write-not-allowed", LIVE_LEAVE_PATH);
|
|
459
|
+
const slot = this.topics.get(topic)?.keys.get(input.key);
|
|
460
|
+
if (!slot)
|
|
461
|
+
return { ended: false };
|
|
462
|
+
const { entry, owner } = slot;
|
|
463
|
+
const allowed = this.admitLeave
|
|
464
|
+
? await this.admitLeave({
|
|
465
|
+
topic,
|
|
466
|
+
key: input.key,
|
|
467
|
+
by: entry.by,
|
|
468
|
+
owner,
|
|
469
|
+
capability: ctx.capability,
|
|
470
|
+
metadata: ctx.metadata,
|
|
471
|
+
...(ctx.principal ? { principal: ctx.principal } : {}),
|
|
472
|
+
})
|
|
473
|
+
: owner !== undefined && owner === ctx.metadata["connectionId"];
|
|
474
|
+
if (!allowed)
|
|
475
|
+
throw refused(`The call cannot end a key of the live topic "${input.topic}"`, "write-not-allowed", LIVE_LEAVE_PATH);
|
|
476
|
+
if (slot.entry !== entry || this.topics.get(topic)?.keys.get(input.key) !== slot)
|
|
477
|
+
return { ended: false };
|
|
478
|
+
return { ended: this.leave(topic, input.key) };
|
|
479
|
+
})
|
|
480
|
+
.build();
|
|
481
|
+
}
|
|
482
|
+
/** The procedure `live.snapshot`: the checks of a subscription, then the live values. */
|
|
483
|
+
snapshotProcedure(topicSchema) {
|
|
484
|
+
return createProcedure()
|
|
485
|
+
.path([...LIVE_SNAPSHOT_PATH])
|
|
486
|
+
.input(z.object({ topic: topicSchema }))
|
|
487
|
+
.output(z.object({ entries: z.array(entrySchema).describe("The live values of the topic") }))
|
|
488
|
+
.meta({
|
|
489
|
+
description: "This procedure gives the live values of a topic. A new subscriber reads it after its subscription starts.",
|
|
490
|
+
effects: { reads: ["events"], writes: [] },
|
|
491
|
+
})
|
|
492
|
+
.handler(async (input, ctx) => {
|
|
493
|
+
const topic = await this.admit(input.topic, ctx);
|
|
494
|
+
if (!liveTopicTarget(topic))
|
|
495
|
+
throw refused(`The topic "${input.topic}" is not a live topic`, "write-not-allowed");
|
|
496
|
+
return { entries: this.snapshot(topic) };
|
|
497
|
+
})
|
|
498
|
+
.build();
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
//# sourceMappingURL=live-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-state.js","sourceRoot":"","sources":["../../src/events/live-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Method } from "../client/types.js";
|
|
2
|
+
import { type LiveEntry } from "./live-state.js";
|
|
3
|
+
import type { RemoteEventHandler, SubscribeOptions, Subscription } from "./remote.js";
|
|
4
|
+
/** The parts of a client that a view uses. A `Client` has them. */
|
|
5
|
+
export interface LiveClient {
|
|
6
|
+
/** This method starts a subscription. */
|
|
7
|
+
subscribe<T = unknown>(topics: string | readonly string[], handler: RemoteEventHandler<T>, options?: SubscribeOptions): Subscription;
|
|
8
|
+
/** This method calls a procedure. */
|
|
9
|
+
call<TReq, TRes>(method: Method, payload: TReq): Promise<TRes>;
|
|
10
|
+
}
|
|
11
|
+
/** The options of a view. */
|
|
12
|
+
export interface LiveViewOptions<T = unknown> extends SubscribeOptions {
|
|
13
|
+
/** This function gets the values after each change. */
|
|
14
|
+
onChange?: ((values: ReadonlyMap<string, LiveEntry<T>>) => void) | undefined;
|
|
15
|
+
/** This function gets the error of a read of the snapshot. The view keeps its values and its subscription. */
|
|
16
|
+
onReadError?: ((error: unknown) => void) | undefined;
|
|
17
|
+
}
|
|
18
|
+
/** The live values of a topic for one reader. */
|
|
19
|
+
export interface LiveView<T = unknown> {
|
|
20
|
+
/** The live values by key. */
|
|
21
|
+
readonly values: ReadonlyMap<string, LiveEntry<T>>;
|
|
22
|
+
/** This promise resolves after the first snapshot. It rejects when the first subscription or read fails. */
|
|
23
|
+
readonly ready: Promise<void>;
|
|
24
|
+
/** This method ends the subscription. A second call does nothing. */
|
|
25
|
+
close(): void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* This function gives a view of a live topic.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const view = liveView(client, liveTopic("presence", "board-1"), { onChange: render });
|
|
33
|
+
* await view.ready;
|
|
34
|
+
* view.close();
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function liveView<T = unknown>(client: LiveClient, topic: string, options?: LiveViewOptions<T>): LiveView<T>;
|
|
38
|
+
//# sourceMappingURL=live-view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-view.d.ts","sourceRoot":"","sources":["../../src/events/live-view.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAsB,KAAK,SAAS,EAAkB,MAAM,iBAAiB,CAAC;AACrF,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEtF,mEAAmE;AACnE,MAAM,WAAW,UAAU;IACzB,yCAAyC;IACzC,SAAS,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,YAAY,CAAC;IACrI,qCAAqC;IACrC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChE;AAED,6BAA6B;AAC7B,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,gBAAgB;IACpE,uDAAuD;IACvD,QAAQ,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC7E,8GAA8G;IAC9G,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CACtD;AAED,iDAAiD;AACjD,MAAM,WAAW,QAAQ,CAAC,CAAC,GAAG,OAAO;IACnC,8BAA8B;IAC9B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,4GAA4G;IAC5G,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,qEAAqE;IACrE,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,eAAe,CAAC,CAAC,CAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAoFtH"}
|