@procedures/store 0.17.3 → 0.18.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 +28 -0
- package/README.md +58 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/browser.d.ts +4 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +3 -0
- package/dist/browser.js.map +1 -1
- package/dist/storage/hybrid.d.ts +9 -0
- package/dist/storage/hybrid.d.ts.map +1 -1
- package/dist/storage/hybrid.js +14 -0
- package/dist/storage/hybrid.js.map +1 -1
- package/dist/storage/index.d.ts +2 -0
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +2 -0
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/tab-coordinator.d.ts +284 -0
- package/dist/storage/tab-coordinator.d.ts.map +1 -0
- package/dist/storage/tab-coordinator.js +584 -0
- package/dist/storage/tab-coordinator.js.map +1 -0
- package/package.json +5 -5
- package/src/browser.ts +11 -0
- package/src/storage/hybrid.ts +14 -0
- package/src/storage/index.ts +10 -0
- package/src/storage/tab-coordinator.ts +692 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The coordinator of the tabs of a browser (roadmap CLI-25, server stack D9).
|
|
3
|
+
*
|
|
4
|
+
* Each tab of a page has a local copy of a collection. Without a coordinator, each tab runs its own
|
|
5
|
+
* `HybridStorage`: each tab pulls, each tab pushes, and the tabs share one queue store. A
|
|
6
|
+
* `TabCoordinator` lets one leader tab run the sync, and the other tabs copy its changes.
|
|
7
|
+
*
|
|
8
|
+
* - The election uses the Web Locks API: the tab that holds the lock of the coordinator is the
|
|
9
|
+
* leader. When the leader closes, or the browser closes its tab, the lock goes to the next tab.
|
|
10
|
+
* - Only the leader makes a `HybridStorage`, with `capture: "observe"` on the local copy. The
|
|
11
|
+
* followers make no remote call, and they run no timer of a sync.
|
|
12
|
+
* - The tabs send the change batches of their local copies on a `BroadcastChannel`. A tab gives the
|
|
13
|
+
* batches of the other tabs to its observers, with their origins.
|
|
14
|
+
* - The leader captures the batches of the followers: its `HybridStorage` queues them and pushes
|
|
15
|
+
* them. Only the leader writes to the queue store, so the tabs can share it by its name.
|
|
16
|
+
* - A follower keeps each own batch until the leader acknowledges it. The leader acknowledges a
|
|
17
|
+
* batch when its queue store holds it. A new leader gets the batches that no leader
|
|
18
|
+
* acknowledged.
|
|
19
|
+
* - Without the Web Locks API or `BroadcastChannel`, the coordinator is in the single mode: the tab
|
|
20
|
+
* is the leader at once, and it opens no channel.
|
|
21
|
+
*
|
|
22
|
+
* The limits:
|
|
23
|
+
* - When the leader stops during a push, the next leader sends the operation again: the delivery to
|
|
24
|
+
* the remote is at least once.
|
|
25
|
+
* - With a shared local copy, a pull of the leader can come between the write of a follower and its
|
|
26
|
+
* capture. The tabs agree again after the push and the next pull.
|
|
27
|
+
* - The load of the queue in a new leader writes the queued operations to the local copy again, and
|
|
28
|
+
* the observers get them again with the origin `syncOrigin`.
|
|
29
|
+
*
|
|
30
|
+
* Nothing in this module reads a global value when it loads: Node can import it. The coordinator
|
|
31
|
+
* reads `navigator.locks` and `BroadcastChannel` when it starts, and a test gives its own.
|
|
32
|
+
*/
|
|
33
|
+
import type { CollectionStorage, StorageObserver } from "@procedures/collections";
|
|
34
|
+
import { type ListenerErrorHandler } from "@procedures/collections";
|
|
35
|
+
import { HybridStorage, type HybridStorageOptions, type LocalCopyStorage } from "./hybrid.js";
|
|
36
|
+
/** The signal that stops a lock request that waits. The `AbortSignal` of a browser fits it. */
|
|
37
|
+
export interface TabAbortSignalLike {
|
|
38
|
+
readonly aborted: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The part of the Web Locks API that the coordinator uses: `navigator.locks` of a browser. The
|
|
42
|
+
* lock is exclusive. The manager calls `callback` when the tab gets the lock, and it holds the lock
|
|
43
|
+
* until the promise of `callback` settles. A test gives a lock manager in memory.
|
|
44
|
+
*/
|
|
45
|
+
export interface TabLockManagerLike {
|
|
46
|
+
request(name: string, options: {
|
|
47
|
+
readonly signal?: TabAbortSignalLike;
|
|
48
|
+
}, callback: (lock: unknown) => Promise<void>): Promise<unknown>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* A channel to the other tabs of the same origin: a `BroadcastChannel` of a browser. A message goes
|
|
52
|
+
* to each other channel of the same name, as a structured clone. The channel does not get its own
|
|
53
|
+
* messages.
|
|
54
|
+
*/
|
|
55
|
+
export interface TabChannelLike {
|
|
56
|
+
postMessage(message: unknown): void;
|
|
57
|
+
onmessage: ((event: any) => void) | null;
|
|
58
|
+
close(): void;
|
|
59
|
+
}
|
|
60
|
+
/** The function that opens a channel with a name. The default opens a `BroadcastChannel`. */
|
|
61
|
+
export type TabChannelFactory = (name: string) => TabChannelLike;
|
|
62
|
+
/**
|
|
63
|
+
* The role of a tab.
|
|
64
|
+
*
|
|
65
|
+
* - `follower`: the tab waits for the lock. It copies the changes of the other tabs, and it sends
|
|
66
|
+
* its own changes to the leader.
|
|
67
|
+
* - `leader`: the tab holds the lock, and its `HybridStorage` runs the sync.
|
|
68
|
+
* - `single`: the browser has no Web Locks API or no `BroadcastChannel`. The tab runs the sync
|
|
69
|
+
* alone, and it opens no channel.
|
|
70
|
+
* - `closed`: after `close()`.
|
|
71
|
+
*/
|
|
72
|
+
export type TabRole = "follower" | "leader" | "single" | "closed";
|
|
73
|
+
/** The options of a `TabCoordinator`. */
|
|
74
|
+
export interface TabCoordinatorOptions<T> {
|
|
75
|
+
/**
|
|
76
|
+
* The name of the coordinator: one name for each collection, the same in each tab. The lock and
|
|
77
|
+
* the channel get it. Give a name for each tenant too.
|
|
78
|
+
*/
|
|
79
|
+
name: string;
|
|
80
|
+
/** The local copy of this tab. It must have `observe()`. The application reads it and writes to it. */
|
|
81
|
+
local: LocalCopyStorage<T>;
|
|
82
|
+
/**
|
|
83
|
+
* The kind of the local copy.
|
|
84
|
+
*
|
|
85
|
+
* - `"shared"`: the tabs open the same durable local copy, for example an `IndexedDbStorage` of
|
|
86
|
+
* one database. A tab does not write the batches of another tab, because they are in the copy.
|
|
87
|
+
* - `"tab"`: each tab has its own local copy, for example a SignalDB collection or an
|
|
88
|
+
* `InMemoryStorage`. A tab writes the batches of the other tabs to its copy.
|
|
89
|
+
*/
|
|
90
|
+
copy: "shared" | "tab";
|
|
91
|
+
/** The function that makes the remote of the `HybridStorage`. Only the leader calls it. */
|
|
92
|
+
remote: () => CollectionStorage<T>;
|
|
93
|
+
/**
|
|
94
|
+
* The options of the `HybridStorage` of the leader. The coordinator sets `local` and
|
|
95
|
+
* `capture: "observe"`. Give the same `queueStore` and `syncState` in each tab, for example an
|
|
96
|
+
* `IndexedDbQueueStore` of one database: a new leader loads the queue of the last leader.
|
|
97
|
+
*/
|
|
98
|
+
hybrid?: Omit<HybridStorageOptions, "local" | "capture">;
|
|
99
|
+
/**
|
|
100
|
+
* The lock manager. `null` sets the single mode.
|
|
101
|
+
* @default `navigator.locks`, when the browser has it
|
|
102
|
+
*/
|
|
103
|
+
locks?: TabLockManagerLike | null;
|
|
104
|
+
/**
|
|
105
|
+
* The function that opens the channel. `null` sets the single mode.
|
|
106
|
+
* @default a function that opens a `BroadcastChannel`, when the browser has it
|
|
107
|
+
*/
|
|
108
|
+
channel?: TabChannelFactory | null;
|
|
109
|
+
/**
|
|
110
|
+
* The function that gets the errors: of the lock, of the channel, of a write to the local copy,
|
|
111
|
+
* of the `HybridStorage` and of the observers. The default throws the error again in a microtask.
|
|
112
|
+
*/
|
|
113
|
+
onError?: ListenerErrorHandler;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* One leader tab runs the sync of a `HybridStorage`, and the other tabs copy its changes.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* import { ApiStorage, IndexedDbQueueStore, IndexedDbStorage, IndexedDbSyncStateStore, TabCoordinator } from "@procedures/store/browser";
|
|
121
|
+
*
|
|
122
|
+
* const local = new IndexedDbStorage<User>("users");
|
|
123
|
+
* const users = new TabCoordinator<User>({
|
|
124
|
+
* name: "users",
|
|
125
|
+
* local,
|
|
126
|
+
* copy: "shared",
|
|
127
|
+
* remote: () => new ApiStorage(client, { collection: "users" }),
|
|
128
|
+
* hybrid: {
|
|
129
|
+
* mode: "write-back",
|
|
130
|
+
* queueStore: new IndexedDbQueueStore("users-queue"),
|
|
131
|
+
* syncState: new IndexedDbSyncStateStore("users-sync"),
|
|
132
|
+
* },
|
|
133
|
+
* });
|
|
134
|
+
*
|
|
135
|
+
* users.observe((batch) => render(batch)); // The changes of this tab and of the other tabs
|
|
136
|
+
* await local.set("1", { name: "Ada" }); // The leader pushes the write
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
export declare class TabCoordinator<T> {
|
|
140
|
+
/** The id of this tab: a new random id for each coordinator. */
|
|
141
|
+
readonly id: string;
|
|
142
|
+
/** The name of the lock and of the channel. */
|
|
143
|
+
readonly lockName: string;
|
|
144
|
+
private readonly local;
|
|
145
|
+
private readonly shared;
|
|
146
|
+
private readonly makeRemote;
|
|
147
|
+
private readonly hybridOptions;
|
|
148
|
+
/** The origin of the `HybridStorage` and of the writes of the coordinator to the local copy. */
|
|
149
|
+
private readonly tag;
|
|
150
|
+
private readonly writeOptions;
|
|
151
|
+
private readonly onError;
|
|
152
|
+
private readonly observers;
|
|
153
|
+
private readonly roleListeners;
|
|
154
|
+
/** The observers that the `HybridStorage` of the leader adds to its local copy: the capture */
|
|
155
|
+
private readonly captures;
|
|
156
|
+
private currentRole;
|
|
157
|
+
private channel;
|
|
158
|
+
private hybrid;
|
|
159
|
+
/** The stop of the observer of the changes of this tab: on the local copy, or on the `HybridStorage` of the leader */
|
|
160
|
+
private stopTap;
|
|
161
|
+
/** True while the leader gives a batch of another tab to the capture of its `HybridStorage` */
|
|
162
|
+
private capturing;
|
|
163
|
+
/** The number of the last batch of this tab */
|
|
164
|
+
private seq;
|
|
165
|
+
/** The batches of this tab that no leader acknowledged, the oldest first */
|
|
166
|
+
private outbox;
|
|
167
|
+
/** The number of the last batch of each other tab that this tab copied */
|
|
168
|
+
private readonly seen;
|
|
169
|
+
/** In the leader: the number of the last batch of each tab that the leader captured. A tab without a hello is not here. */
|
|
170
|
+
private readonly captured;
|
|
171
|
+
/** The batches of the other tabs: they reach the local copy and the observers in their order */
|
|
172
|
+
private incoming;
|
|
173
|
+
private closed;
|
|
174
|
+
private closing;
|
|
175
|
+
/** The abort of the lock request that waits */
|
|
176
|
+
private abortRequest;
|
|
177
|
+
/** The release of the lock */
|
|
178
|
+
private releaseLock;
|
|
179
|
+
constructor(options: TabCoordinatorOptions<T>);
|
|
180
|
+
/** The role of this tab now. */
|
|
181
|
+
get role(): TabRole;
|
|
182
|
+
/** True when this tab runs the sync: the leader, or a tab in the single mode. */
|
|
183
|
+
get isLeader(): boolean;
|
|
184
|
+
/**
|
|
185
|
+
* The `HybridStorage` of the sync while this tab runs it, or else undefined. Its `getStatus()`
|
|
186
|
+
* gives the state of the sync. Write to the local copy, not to this storage: each tab then writes
|
|
187
|
+
* in the same way.
|
|
188
|
+
*/
|
|
189
|
+
get syncStorage(): HybridStorage<T> | undefined;
|
|
190
|
+
/**
|
|
191
|
+
* This method starts to send the change batches to an observer: the batches of the local copy of
|
|
192
|
+
* this tab, and the batches of the other tabs. Each batch comes one time, with the origin of each
|
|
193
|
+
* change. In the leader, the batches of the sync have the origin `syncOrigin` of the
|
|
194
|
+
* `HybridStorage`. A batch of another tab comes after the local copy of this tab has it.
|
|
195
|
+
*
|
|
196
|
+
* @returns The function that stops the batches. A second use of it does nothing.
|
|
197
|
+
* @throws Error after `close()`
|
|
198
|
+
*/
|
|
199
|
+
observe(observer: StorageObserver<T>): () => void;
|
|
200
|
+
/**
|
|
201
|
+
* This method starts to send the role of this tab to a listener at each change.
|
|
202
|
+
*
|
|
203
|
+
* @returns The function that stops the roles. A second use of it does nothing.
|
|
204
|
+
* @throws Error after `close()`
|
|
205
|
+
*/
|
|
206
|
+
onRole(listener: (role: TabRole) => void): () => void;
|
|
207
|
+
/**
|
|
208
|
+
* This method closes the coordinator.
|
|
209
|
+
*
|
|
210
|
+
* - A follower stops its lock request. It does not become the leader.
|
|
211
|
+
* - The leader closes its `HybridStorage`: it sends the queue, and the queue store keeps the
|
|
212
|
+
* operations that the remote did not take. Then the leader releases the lock, and the next
|
|
213
|
+
* tab becomes the leader.
|
|
214
|
+
* - The coordinator closes its channel. It does not close the local copy: the application owns it.
|
|
215
|
+
* - After it, the coordinator sends and copies nothing. A second `close()` gives the promise of
|
|
216
|
+
* the first one.
|
|
217
|
+
*/
|
|
218
|
+
close(): Promise<void>;
|
|
219
|
+
private shutDown;
|
|
220
|
+
/** This method asks for the lock. The tab becomes the leader when it gets the lock. */
|
|
221
|
+
private elect;
|
|
222
|
+
/**
|
|
223
|
+
* This method makes the `HybridStorage` of the sync: the tab becomes the leader, or the single
|
|
224
|
+
* tab. The capture of the storage gets the batches of this tab that no leader acknowledged.
|
|
225
|
+
*
|
|
226
|
+
* @returns False when the storage could not start
|
|
227
|
+
*/
|
|
228
|
+
private lead;
|
|
229
|
+
/**
|
|
230
|
+
* The local copy for the `HybridStorage` of the leader. Its `observe()` gives the changes of the
|
|
231
|
+
* local copy and the batches of the other tabs, so the capture queues both. Its `close()` does
|
|
232
|
+
* nothing: the application owns the local copy.
|
|
233
|
+
*/
|
|
234
|
+
private captureCopy;
|
|
235
|
+
/**
|
|
236
|
+
* This method gives a batch of another tab to the capture of the `HybridStorage` of the leader.
|
|
237
|
+
* The storage queues it. Its observers get it at once, and the coordinator ignores it there: the
|
|
238
|
+
* observers of the coordinator get it from the channel.
|
|
239
|
+
*/
|
|
240
|
+
private capture;
|
|
241
|
+
private setRole;
|
|
242
|
+
/**
|
|
243
|
+
* A batch of the local copy of a follower. The writes of the coordinator itself (the batches of
|
|
244
|
+
* the other tabs in a copy of each tab) have the tag of the coordinator, and do not go out again.
|
|
245
|
+
*/
|
|
246
|
+
private onFollowerBatch;
|
|
247
|
+
/**
|
|
248
|
+
* A batch of the `HybridStorage` of the leader: a write of the application to the local copy,
|
|
249
|
+
* a write to the storage, or a change of the sync.
|
|
250
|
+
*/
|
|
251
|
+
private onLeaderBatch;
|
|
252
|
+
/** This method gives a batch of this tab to its observers and to the other tabs. A follower keeps it for the leader. */
|
|
253
|
+
private share;
|
|
254
|
+
/** This method tells the leader the batches of this tab that no leader acknowledged. */
|
|
255
|
+
private hello;
|
|
256
|
+
/** @returns False when the message did not go out: no channel, or a value that the channel cannot clone */
|
|
257
|
+
private post;
|
|
258
|
+
private stopChannel;
|
|
259
|
+
private receive;
|
|
260
|
+
/**
|
|
261
|
+
* A batch of another tab. The leader captures it when the tab said hello to it. Each tab copies
|
|
262
|
+
* it one time.
|
|
263
|
+
*/
|
|
264
|
+
private onChanges;
|
|
265
|
+
/**
|
|
266
|
+
* The hello of another tab. The leader captures the batches that it did not capture, and then each
|
|
267
|
+
* batch of the tab after `seq`. Each tab copies the batches that it did not see.
|
|
268
|
+
*/
|
|
269
|
+
private onHello;
|
|
270
|
+
/**
|
|
271
|
+
* This method copies a batch of another tab that this tab did not see: to the local copy of a
|
|
272
|
+
* tab, and then to the observers. The batches go in their order.
|
|
273
|
+
*/
|
|
274
|
+
private copy;
|
|
275
|
+
/**
|
|
276
|
+
* This method writes a batch of another tab to the local copy of this tab, with the tag of the
|
|
277
|
+
* coordinator: the observer of this tab and the capture of the leader ignore the writes. The sets
|
|
278
|
+
* in a row go in one `setBatch`, and the deletes in a row in one `deleteBatch`.
|
|
279
|
+
*/
|
|
280
|
+
private write;
|
|
281
|
+
/** This method tells a tab that the queue store of the leader holds its batches up to `seq`. */
|
|
282
|
+
private acknowledge;
|
|
283
|
+
}
|
|
284
|
+
//# sourceMappingURL=tab-coordinator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tab-coordinator.d.ts","sourceRoot":"","sources":["../../src/storage/tab-coordinator.ts"],"names":[],"mappings":"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"}
|