@procedures/store 0.24.0 → 0.25.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 +33 -0
- package/README.md +59 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/browser.d.ts +3 -2
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +2 -1
- package/dist/browser.js.map +1 -1
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +1 -1
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/tab-coordinator.d.ts +194 -145
- package/dist/storage/tab-coordinator.d.ts.map +1 -1
- package/dist/storage/tab-coordinator.js +1018 -251
- package/dist/storage/tab-coordinator.js.map +1 -1
- package/package.json +4 -4
- package/src/browser.ts +6 -1
- package/src/storage/index.ts +5 -1
- package/src/storage/tab-coordinator.ts +1199 -256
package/dist/browser.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* - `EventsChangeFeed` pushes the remote changes to a `HybridStorage`.
|
|
8
8
|
* - `TabCoordinator` lets one leader tab run the sync of a `HybridStorage`, and the other tabs
|
|
9
9
|
* copy its changes (roadmap CLI-25). It uses the Web Locks API and `BroadcastChannel`.
|
|
10
|
+
* - `TabGroup` does the same for many collections, with one lock and one channel (roadmap CLI-64).
|
|
10
11
|
* - The entry also has all of `@procedures/store/indexeddb`: `IndexedDbStorage`, the IndexedDB
|
|
11
12
|
* stores and their fallbacks in memory.
|
|
12
13
|
*
|
|
@@ -20,8 +21,8 @@
|
|
|
20
21
|
export * from "./indexeddb.js";
|
|
21
22
|
export { HybridStorage, PendingWriteError, QueueFullError, MissingKeysError, QueueStoreError, ConflictError, ModeSwitchError, SyncStateError, } from "./storage/hybrid.js";
|
|
22
23
|
export type { HybridStorageOptions, HybridMode, LocalCopyStorage } from "./storage/hybrid.js";
|
|
23
|
-
export { TabCoordinator } from "./storage/tab-coordinator.js";
|
|
24
|
-
export type { TabAbortSignalLike, TabChannelFactory, TabChannelLike, TabCoordinatorOptions, TabLockManagerLike, TabRetryOptions, TabRole, } from "./storage/tab-coordinator.js";
|
|
24
|
+
export { TabCoordinator, TabGroup } from "./storage/tab-coordinator.js";
|
|
25
|
+
export type { TabAbortSignalLike, TabChannelFactory, TabChannelLike, TabCollection, TabCollectionOptions, TabCoordinatorOptions, TabGroupOptions, TabLockManagerLike, TabRetryOptions, TabRole, TabSnapshotOptions, } from "./storage/tab-coordinator.js";
|
|
25
26
|
export type { ConflictResolution, SyncError, SyncStatus } from "./storage/types.js";
|
|
26
27
|
export { ApiStorage } from "./storage/api.js";
|
|
27
28
|
export type { ApiStorageOptions } from "./storage/api.js";
|
package/dist/browser.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,oBAAoB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC9F,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxE,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,OAAO,EACP,kBAAkB,GACnB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EAAE,kBAAkB,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,uBAAuB,EACvB,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,GACd,MAAM,mBAAmB,CAAC"}
|
package/dist/browser.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* - `EventsChangeFeed` pushes the remote changes to a `HybridStorage`.
|
|
8
8
|
* - `TabCoordinator` lets one leader tab run the sync of a `HybridStorage`, and the other tabs
|
|
9
9
|
* copy its changes (roadmap CLI-25). It uses the Web Locks API and `BroadcastChannel`.
|
|
10
|
+
* - `TabGroup` does the same for many collections, with one lock and one channel (roadmap CLI-64).
|
|
10
11
|
* - The entry also has all of `@procedures/store/indexeddb`: `IndexedDbStorage`, the IndexedDB
|
|
11
12
|
* stores and their fallbacks in memory.
|
|
12
13
|
*
|
|
@@ -19,7 +20,7 @@
|
|
|
19
20
|
*/
|
|
20
21
|
export * from "./indexeddb.js";
|
|
21
22
|
export { HybridStorage, PendingWriteError, QueueFullError, MissingKeysError, QueueStoreError, ConflictError, ModeSwitchError, SyncStateError, } from "./storage/hybrid.js";
|
|
22
|
-
export { TabCoordinator } from "./storage/tab-coordinator.js";
|
|
23
|
+
export { TabCoordinator, TabGroup } from "./storage/tab-coordinator.js";
|
|
23
24
|
export { ApiStorage } from "./storage/api.js";
|
|
24
25
|
export { EventsChangeFeed } from "./storage/feed.js";
|
|
25
26
|
//# sourceMappingURL=browser.js.map
|
package/dist/browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAexE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/storage/index.d.ts
CHANGED
|
@@ -11,8 +11,8 @@ export { ApiStorage } from "./api.js";
|
|
|
11
11
|
export type { ApiStorageOptions } from "./api.js";
|
|
12
12
|
export { HybridStorage, PendingWriteError, QueueFullError, MissingKeysError, QueueStoreError, ConflictError, ModeSwitchError, SyncStateError, } from "./hybrid.js";
|
|
13
13
|
export type { HybridStorageOptions, HybridMode, LocalCopyStorage } from "./hybrid.js";
|
|
14
|
-
export { TabCoordinator } from "./tab-coordinator.js";
|
|
15
|
-
export type { TabAbortSignalLike, TabChannelFactory, TabChannelLike, TabCoordinatorOptions, TabLockManagerLike, TabRetryOptions, TabRole, } from "./tab-coordinator.js";
|
|
14
|
+
export { TabCoordinator, TabGroup } from "./tab-coordinator.js";
|
|
15
|
+
export type { TabAbortSignalLike, TabChannelFactory, TabChannelLike, TabCollection, TabCollectionOptions, TabCoordinatorOptions, TabGroupOptions, TabLockManagerLike, TabRetryOptions, TabRole, TabSnapshotOptions, } from "./tab-coordinator.js";
|
|
16
16
|
export { EventsChangeFeed } from "./feed.js";
|
|
17
17
|
export type { ChangeEventSource, EventSubscriber, EventsChangeFeedOptions, RemoteChangeFeed, RemoteChangeHint, RemoteChangeListener, RemoteChanges, } from "./feed.js";
|
|
18
18
|
export { MemorySyncStateStore } from "./sync-state.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,UAAU,EACV,UAAU,EACV,SAAS,EACT,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,EACxB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAG/E,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,YAAY,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,oBAAoB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEtF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,UAAU,EACV,UAAU,EACV,SAAS,EACT,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,EACxB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAG/E,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,YAAY,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,oBAAoB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEtF,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChE,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,OAAO,EACP,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,uBAAuB,EACvB,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,GACd,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIlF,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,YAAY,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAC;AAGnE,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAClF,YAAY,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAGtE,OAAO,EACL,oBAAoB,EACpB,0BAA0B,EAC1B,uBAAuB,EACvB,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAG/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/storage/index.js
CHANGED
|
@@ -10,7 +10,7 @@ export { serializeProcedure, deserializeProcedure, deserializeProcedureSync, get
|
|
|
10
10
|
export { ApiStorage } from "./api.js";
|
|
11
11
|
export { HybridStorage, PendingWriteError, QueueFullError, MissingKeysError, QueueStoreError, ConflictError, ModeSwitchError, SyncStateError, } from "./hybrid.js";
|
|
12
12
|
// One leader tab runs the sync, and the other tabs copy its changes (roadmap CLI-25)
|
|
13
|
-
export { TabCoordinator } from "./tab-coordinator.js";
|
|
13
|
+
export { TabCoordinator, TabGroup } from "./tab-coordinator.js";
|
|
14
14
|
// The push feed of the remote changes (roadmap CLI-21, CLI-15)
|
|
15
15
|
export { EventsChangeFeed } from "./feed.js";
|
|
16
16
|
// The sync state of HybridStorage: the cursor and the base versions (roadmap CLI-21).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAkBH,gBAAgB;AAChB,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,EACxB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAG5B,wFAAwF;AACxF,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,aAAa,CAAC;AAErB,qFAAqF;AACrF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAkBH,gBAAgB;AAChB,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,EACxB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAG5B,wFAAwF;AACxF,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,aAAa,CAAC;AAErB,qFAAqF;AACrF,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAchE,+DAA+D;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAU7C,sFAAsF;AACtF,+DAA+D;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEvD,+EAA+E;AAC/E,6EAA6E;AAC7E,mFAAmF;AACnF,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG9C,UAAU;AACV,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAGvD,kBAAkB;AAClB,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAGlF,UAAU;AACV,OAAO,EACL,oBAAoB,EACpB,0BAA0B,EAC1B,uBAAuB,EACvB,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,cAAc,CAAC;AAGtB,0EAA0E;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -25,6 +25,39 @@
|
|
|
25
25
|
* - The leader sends the status of its sync to the followers: at each change, and in answer to a
|
|
26
26
|
* hello. `getStatus()` and `onStatus()` give the status in each tab (roadmap CLI-65).
|
|
27
27
|
*
|
|
28
|
+
* A `TabGroup` runs the sync of many collections with one lock and one channel (roadmap CLI-64),
|
|
29
|
+
* for example all the collections of a tenant.
|
|
30
|
+
*
|
|
31
|
+
* - The leader of the group runs one `HybridStorage` for each collection. Each message has the
|
|
32
|
+
* field `collection`, and each collection has its own batches, acknowledgements and status.
|
|
33
|
+
* - Each collection leads when its own queue loaded, and it tells the other tabs at once. Thus a
|
|
34
|
+
* slow collection does not stop the batches of the other collections.
|
|
35
|
+
* - A collection whose setup fails tries again alone after its backoff, and the other collections
|
|
36
|
+
* keep their sync. The tab sends a status with the error of the setup to the other tabs.
|
|
37
|
+
* - When no collection of the group leads or loads its queue, the tab releases the lock. It asks for
|
|
38
|
+
* the lock again after the backoff of the group, as a `TabCoordinator` does. This is also true for
|
|
39
|
+
* a collection that the application adds after the tab got the lock.
|
|
40
|
+
* - The lock and the channel of a group have the prefix `@procedures/store/tabs:`. A
|
|
41
|
+
* `TabCoordinator` has the prefix `@procedures/store/tab:`. Thus a group and a coordinator never
|
|
42
|
+
* share a lock or a channel, also with the same name.
|
|
43
|
+
* - With the option `open`, the leader makes a collection that another tab has and that this tab
|
|
44
|
+
* does not have. Thus the tabs can open different collections.
|
|
45
|
+
*
|
|
46
|
+
* A snapshot for a new tab (roadmap CLI-66): with `copy: "tab"` and the option `snapshot`, a new
|
|
47
|
+
* tab asks the leader for the entries of its local copy.
|
|
48
|
+
*
|
|
49
|
+
* - The leader reads the entries of its copy, and it sends them in chunks of `snapshot.chunk`
|
|
50
|
+
* entries. Each chunk has the numbers of the last batches that the copy holds, one for each tab.
|
|
51
|
+
* - The new tab keeps the batches of the other tabs until the last chunk comes. It writes the
|
|
52
|
+
* entries to its copy, and then it writes the batches with a number after the snapshot.
|
|
53
|
+
* - The new tab keeps the values of its own writes after the snapshot.
|
|
54
|
+
* - A set in the entries can come again in a batch after the snapshot, for example a write of the
|
|
55
|
+
* leader during its read. The second write of the set gives the same state.
|
|
56
|
+
* - When the leader changes before the last chunk, the tab asks the new leader. When no chunk comes
|
|
57
|
+
* in the time `snapshot.timeout`, the tab reports an error and continues without the snapshot.
|
|
58
|
+
* - In the tab that holds the lock, the wait renews itself while the collection loads its queue, at
|
|
59
|
+
* most `SNAPSHOT_RENEWALS` times. Thus the batches of the other tabs wait for a limited time.
|
|
60
|
+
*
|
|
28
61
|
* The limits:
|
|
29
62
|
* - When the leader stops during a push, the next leader sends the operation again: the delivery to
|
|
30
63
|
* the remote is at least once.
|
|
@@ -32,6 +65,12 @@
|
|
|
32
65
|
* capture. The tabs agree again after the push and the next pull.
|
|
33
66
|
* - The load of the queue in a new leader writes the queued operations to the local copy again, and
|
|
34
67
|
* the observers get them again with the origin `syncOrigin`.
|
|
68
|
+
* - The leader reads all the entries of a snapshot at one time, and the new tab keeps all the chunks
|
|
69
|
+
* until the last one. Thus a snapshot is for a local copy that fits in the memory of a tab.
|
|
70
|
+
* - `snapshot.chunk` counts the entries of a message, not its bytes: large items give large messages.
|
|
71
|
+
* - A `TabCoordinator` and a `TabGroup` of one collection do not see each other. When tabs of both
|
|
72
|
+
* releases are open, two tabs lead the collection. Give the group a new queue store, or close
|
|
73
|
+
* the tabs of the older release first.
|
|
35
74
|
*
|
|
36
75
|
* Nothing in this module reads a global value when it loads: Node can import it. The coordinator
|
|
37
76
|
* reads `navigator.locks` and `BroadcastChannel` when it starts, and a test gives its own.
|
|
@@ -68,7 +107,7 @@ export interface TabChannelLike {
|
|
|
68
107
|
/** The function that opens a channel with a name. The default opens a `BroadcastChannel`. */
|
|
69
108
|
export type TabChannelFactory = (name: string) => TabChannelLike;
|
|
70
109
|
/**
|
|
71
|
-
* The role of a tab.
|
|
110
|
+
* The role of a tab, or of a collection of a `TabGroup` in a tab.
|
|
72
111
|
*
|
|
73
112
|
* - `follower`: the tab waits for the lock. It copies the changes of the other tabs, and it sends
|
|
74
113
|
* its own changes to the leader. A tab whose setup failed is a follower until its next try.
|
|
@@ -76,13 +115,16 @@ export type TabChannelFactory = (name: string) => TabChannelLike;
|
|
|
76
115
|
* - `single`: the browser has no Web Locks API or no `BroadcastChannel`. The tab runs the sync
|
|
77
116
|
* alone, and it opens no channel.
|
|
78
117
|
* - `closed`: after `close()`.
|
|
118
|
+
*
|
|
119
|
+
* A `TabGroup` is `leader` when it holds the lock. Each collection of the group is `leader` only
|
|
120
|
+
* when its own `HybridStorage` runs.
|
|
79
121
|
*/
|
|
80
122
|
export type TabRole = "follower" | "leader" | "single" | "closed";
|
|
81
123
|
/** The options of a `TabCoordinator`. */
|
|
82
124
|
export interface TabCoordinatorOptions<T> {
|
|
83
125
|
/**
|
|
84
126
|
* The name of the coordinator: one name for each collection, the same in each tab. The lock and
|
|
85
|
-
* the channel get it. Give a name for each tenant too.
|
|
127
|
+
* the channel get it. Give a name for each tenant too. For many collections, use a `TabGroup`.
|
|
86
128
|
*/
|
|
87
129
|
name: string;
|
|
88
130
|
/** The local copy of this tab. It must have `observe()`. The application reads it and writes to it. */
|
|
@@ -107,6 +149,12 @@ export interface TabCoordinatorOptions<T> {
|
|
|
107
149
|
* `IndexedDbQueueStore` of one database: a new leader loads the queue of the last leader.
|
|
108
150
|
*/
|
|
109
151
|
hybrid?: Omit<HybridStorageOptions, "local" | "capture">;
|
|
152
|
+
/**
|
|
153
|
+
* The snapshot for a new tab (roadmap CLI-66). Only `copy: "tab"` takes it. With it, a new tab
|
|
154
|
+
* asks the leader for the entries of its local copy. Give it to a local copy that starts empty.
|
|
155
|
+
* @default false
|
|
156
|
+
*/
|
|
157
|
+
snapshot?: boolean | TabSnapshotOptions;
|
|
110
158
|
/**
|
|
111
159
|
* The lock manager. `null` sets the single mode.
|
|
112
160
|
* @default `navigator.locks`, when the browser has it
|
|
@@ -129,7 +177,8 @@ export interface TabCoordinatorOptions<T> {
|
|
|
129
177
|
*/
|
|
130
178
|
retry?: TabRetryOptions;
|
|
131
179
|
/**
|
|
132
|
-
* The clock of the wait of `retry`. A test gives `fakeClock` of
|
|
180
|
+
* The clock of the wait of `retry` and of `snapshot.timeout`. A test gives `fakeClock` of
|
|
181
|
+
* `@mark1russell7/service/testing`.
|
|
133
182
|
* @default the `clock` of `hybrid`, or else the clock of the platform (`realClock` of `@procedures/client`)
|
|
134
183
|
*/
|
|
135
184
|
clock?: Clock;
|
|
@@ -140,8 +189,8 @@ export interface TabCoordinatorOptions<T> {
|
|
|
140
189
|
random?: () => number;
|
|
141
190
|
/**
|
|
142
191
|
* The function that gets the errors: of the lock, of the channel, of a write to the local copy,
|
|
143
|
-
* of the `HybridStorage`, of a failed setup and of the observers. The default
|
|
144
|
-
* again in a microtask.
|
|
192
|
+
* of the `HybridStorage`, of a failed setup, of a snapshot and of the observers. The default
|
|
193
|
+
* throws the error again in a microtask.
|
|
145
194
|
*/
|
|
146
195
|
onError?: ListenerErrorHandler;
|
|
147
196
|
}
|
|
@@ -156,6 +205,90 @@ export interface TabRetryOptions {
|
|
|
156
205
|
/** The random part of each wait, from 0 to 1. The wait is from `(1 − jitter) ×` the backoff up to the backoff. @default 0.5 */
|
|
157
206
|
jitter?: number;
|
|
158
207
|
}
|
|
208
|
+
/** The options of the snapshot for a new tab (roadmap CLI-66). */
|
|
209
|
+
export interface TabSnapshotOptions {
|
|
210
|
+
/**
|
|
211
|
+
* The largest number of entries in one message of the snapshot, 1 or more. The leader uses its
|
|
212
|
+
* own value when it sends a snapshot. It does not limit the bytes: large items give large messages.
|
|
213
|
+
* @default 500
|
|
214
|
+
*/
|
|
215
|
+
chunk?: number;
|
|
216
|
+
/**
|
|
217
|
+
* The longest wait for the next message of the snapshot, for example `seconds(10)`. After it, the
|
|
218
|
+
* tab gives an error to `onError`, and it copies the batches of the other tabs without a snapshot.
|
|
219
|
+
* In the tab that holds the lock, the wait renews itself while the collection loads its queue, at
|
|
220
|
+
* most 5 times.
|
|
221
|
+
* @default 10 seconds
|
|
222
|
+
*/
|
|
223
|
+
timeout?: Duration;
|
|
224
|
+
}
|
|
225
|
+
/** The options of one collection of a `TabGroup` (roadmap CLI-64). */
|
|
226
|
+
export interface TabCollectionOptions<T> {
|
|
227
|
+
/** The local copy of the collection in this tab. It must have `observe()`. */
|
|
228
|
+
local: LocalCopyStorage<T>;
|
|
229
|
+
/** The kind of the local copy: `"shared"` or `"tab"`, as the option `copy` of a `TabCoordinator`. */
|
|
230
|
+
copy: "shared" | "tab";
|
|
231
|
+
/** The function that makes the remote of the collection. Only the leader calls it. */
|
|
232
|
+
remote: () => CollectionStorage<T>;
|
|
233
|
+
/**
|
|
234
|
+
* The options of the `HybridStorage` of the collection in the leader. Give a `queueStore` for each
|
|
235
|
+
* collection, the same in each tab.
|
|
236
|
+
*/
|
|
237
|
+
hybrid?: Omit<HybridStorageOptions, "local" | "capture">;
|
|
238
|
+
/** The snapshot for a new tab (roadmap CLI-66), as the option `snapshot` of a `TabCoordinator`. @default false */
|
|
239
|
+
snapshot?: boolean | TabSnapshotOptions;
|
|
240
|
+
}
|
|
241
|
+
/** The options of a `TabGroup` (roadmap CLI-64). */
|
|
242
|
+
export interface TabGroupOptions {
|
|
243
|
+
/**
|
|
244
|
+
* The name of the group, the same in each tab, for example the name of a tenant. The lock and the
|
|
245
|
+
* channel get it.
|
|
246
|
+
*/
|
|
247
|
+
name: string;
|
|
248
|
+
/**
|
|
249
|
+
* The function that gives the options of a collection with its name. `collection(name)` uses it
|
|
250
|
+
* without options. The leader also uses it for a collection that only another tab opened. It
|
|
251
|
+
* gives `undefined` for a collection without a sync.
|
|
252
|
+
*/
|
|
253
|
+
open?: (collection: string) => TabCollectionOptions<any> | undefined;
|
|
254
|
+
/** The lock manager. `null` sets the single mode. @default `navigator.locks`, when the browser has it */
|
|
255
|
+
locks?: TabLockManagerLike | null;
|
|
256
|
+
/** The function that opens the channel. `null` sets the single mode. @default a `BroadcastChannel`, when the browser has it */
|
|
257
|
+
channel?: TabChannelFactory | null;
|
|
258
|
+
/**
|
|
259
|
+
* The backoff of a new try after a failed setup (roadmap CLI-67). The group and each collection
|
|
260
|
+
* count their failures. A collection whose setup fails in the leader tries again alone.
|
|
261
|
+
*/
|
|
262
|
+
retry?: TabRetryOptions;
|
|
263
|
+
/** The clock of the waits. @default the clock of the platform (`realClock` of `@procedures/client`) */
|
|
264
|
+
clock?: Clock;
|
|
265
|
+
/** The random numbers of the jitter of `retry`, from 0 up to 1. @default `Math.random` */
|
|
266
|
+
random?: () => number;
|
|
267
|
+
/** The function that gets the errors of the group and of its collections. The default throws the error again in a microtask. */
|
|
268
|
+
onError?: ListenerErrorHandler;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* One collection of a `TabGroup` in this tab (roadmap CLI-64). It has the methods of a
|
|
272
|
+
* `TabCoordinator` for one collection, except `close()`: `close()` of the group closes it.
|
|
273
|
+
*/
|
|
274
|
+
export interface TabCollection<T> {
|
|
275
|
+
/** The name of the collection in the group. */
|
|
276
|
+
readonly name: string;
|
|
277
|
+
/** The role of this collection in this tab: `leader` or `single` only while its `HybridStorage` runs. */
|
|
278
|
+
readonly role: TabRole;
|
|
279
|
+
/** True when this tab runs the sync of this collection. */
|
|
280
|
+
readonly isLeader: boolean;
|
|
281
|
+
/** The `HybridStorage` of the collection while this tab runs its sync, or else undefined. */
|
|
282
|
+
readonly syncStorage: HybridStorage<T> | undefined;
|
|
283
|
+
/** This method starts to send the change batches of the collection to an observer, as `TabCoordinator.observe()`. */
|
|
284
|
+
observe(observer: StorageObserver<T>): () => void;
|
|
285
|
+
/** This method starts to send the role of the collection to a listener at each change. */
|
|
286
|
+
onRole(listener: (role: TabRole) => void): () => void;
|
|
287
|
+
/** The status of the sync of the collection (roadmap CLI-65), as `TabCoordinator.getStatus()`. */
|
|
288
|
+
getStatus(): SyncStatus | undefined;
|
|
289
|
+
/** This method starts to send the status of the sync of the collection to a listener at each change. */
|
|
290
|
+
onStatus(listener: (status: SyncStatus) => void): () => void;
|
|
291
|
+
}
|
|
159
292
|
/**
|
|
160
293
|
* One leader tab runs the sync of a `HybridStorage`, and the other tabs copy its changes.
|
|
161
294
|
*
|
|
@@ -186,61 +319,8 @@ export declare class TabCoordinator<T> {
|
|
|
186
319
|
readonly id: string;
|
|
187
320
|
/** The name of the lock and of the channel. */
|
|
188
321
|
readonly lockName: string;
|
|
189
|
-
private readonly
|
|
190
|
-
private readonly
|
|
191
|
-
private readonly makeRemote;
|
|
192
|
-
private readonly hybridOptions;
|
|
193
|
-
/** The origin of the `HybridStorage` and of the writes of the coordinator to the local copy. */
|
|
194
|
-
private readonly tag;
|
|
195
|
-
private readonly writeOptions;
|
|
196
|
-
private readonly onError;
|
|
197
|
-
private readonly observers;
|
|
198
|
-
private readonly roleListeners;
|
|
199
|
-
private readonly statusListeners;
|
|
200
|
-
/** The observers that the `HybridStorage` of the leader adds to its local copy: the capture */
|
|
201
|
-
private readonly captures;
|
|
202
|
-
/** The backoff of a new try after a failed setup, its clock and its random numbers */
|
|
203
|
-
private readonly backoff;
|
|
204
|
-
private readonly clock;
|
|
205
|
-
private readonly random;
|
|
206
|
-
private currentRole;
|
|
207
|
-
/** The lock manager, or undefined in the single mode */
|
|
208
|
-
private locks;
|
|
209
|
-
private channel;
|
|
210
|
-
private hybrid;
|
|
211
|
-
/** The storage of this tab while it loads its queue, before the tab leads */
|
|
212
|
-
private candidate;
|
|
213
|
-
/** The number of the failed setups in a row */
|
|
214
|
-
private failures;
|
|
215
|
-
/** The stop of the wait before the next try */
|
|
216
|
-
private cancelRetry;
|
|
217
|
-
/** The status of the sync: of the `HybridStorage` of this tab, or of the leader */
|
|
218
|
-
private status;
|
|
219
|
-
/** In the leader: the number of its last status. In a follower: the tab and the number of the last status that it got. */
|
|
220
|
-
private statusSeq;
|
|
221
|
-
private statusFrom;
|
|
222
|
-
/** The stop of the status of the `HybridStorage` of this tab */
|
|
223
|
-
private stopStatus;
|
|
224
|
-
/** The stop of the observer of the changes of this tab: on the local copy, or on the `HybridStorage` of the leader */
|
|
225
|
-
private stopTap;
|
|
226
|
-
/** True while the leader gives a batch of another tab to the capture of its `HybridStorage` */
|
|
227
|
-
private capturing;
|
|
228
|
-
/** The number of the last batch of this tab */
|
|
229
|
-
private seq;
|
|
230
|
-
/** The batches of this tab that no leader acknowledged, the oldest first */
|
|
231
|
-
private outbox;
|
|
232
|
-
/** The number of the last batch of each other tab that this tab copied */
|
|
233
|
-
private readonly seen;
|
|
234
|
-
/** In the leader: the number of the last batch of each tab that the leader captured. A tab without a hello is not here. */
|
|
235
|
-
private readonly captured;
|
|
236
|
-
/** The batches of the other tabs: they reach the local copy and the observers in their order */
|
|
237
|
-
private incoming;
|
|
238
|
-
private closed;
|
|
239
|
-
private closing;
|
|
240
|
-
/** The abort of the lock request that waits */
|
|
241
|
-
private abortRequest;
|
|
242
|
-
/** The release of the lock */
|
|
243
|
-
private releaseLock;
|
|
322
|
+
private readonly group;
|
|
323
|
+
private readonly collection;
|
|
244
324
|
constructor(options: TabCoordinatorOptions<T>);
|
|
245
325
|
/** The role of this tab now. */
|
|
246
326
|
get role(): TabRole;
|
|
@@ -256,7 +336,9 @@ export declare class TabCoordinator<T> {
|
|
|
256
336
|
* This method starts to send the change batches to an observer: the batches of the local copy of
|
|
257
337
|
* this tab, and the batches of the other tabs. Each batch comes one time, with the origin of each
|
|
258
338
|
* change. In the leader, the batches of the sync have the origin `syncOrigin` of the
|
|
259
|
-
* `HybridStorage`. A batch of another tab comes after the local copy of this tab has it.
|
|
339
|
+
* `HybridStorage`. A batch of another tab comes after the local copy of this tab has it. The
|
|
340
|
+
* entries of a snapshot come in one batch of sets, with the origin `syncOrigin`. A set of the
|
|
341
|
+
* snapshot can come again in a later batch, with the same value.
|
|
260
342
|
*
|
|
261
343
|
* @returns The function that stops the batches. A second use of it does nothing.
|
|
262
344
|
* @throws Error after `close()`
|
|
@@ -304,97 +386,64 @@ export declare class TabCoordinator<T> {
|
|
|
304
386
|
* the first one.
|
|
305
387
|
*/
|
|
306
388
|
close(): Promise<void>;
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* One leader tab runs the sync of many collections, with one lock and one channel (roadmap CLI-64).
|
|
392
|
+
* The other tabs copy the changes of each collection.
|
|
393
|
+
*
|
|
394
|
+
* @example
|
|
395
|
+
* ```typescript
|
|
396
|
+
* import { ApiStorage, IndexedDbQueueStore, TabGroup } from "@procedures/store/browser";
|
|
397
|
+
*
|
|
398
|
+
* const tenant = new TabGroup({
|
|
399
|
+
* name: tenantId,
|
|
400
|
+
* open: (collection) => ({
|
|
401
|
+
* local: localCopyOf(collection),
|
|
402
|
+
* copy: "tab",
|
|
403
|
+
* remote: () => new ApiStorage(client, { collection }),
|
|
404
|
+
* hybrid: { queueStore: new IndexedDbQueueStore(`${tenantId}-${collection}-queue`) },
|
|
405
|
+
* snapshot: true,
|
|
406
|
+
* }),
|
|
407
|
+
* });
|
|
408
|
+
*
|
|
409
|
+
* const notes = tenant.collection<Note>("notes");
|
|
410
|
+
* notes.observe((batch) => render(batch));
|
|
411
|
+
* notes.onStatus((status) => showSync("notes", status));
|
|
412
|
+
* ```
|
|
413
|
+
*/
|
|
414
|
+
export declare class TabGroup {
|
|
415
|
+
/** The id of this tab: a new random id for each group. */
|
|
416
|
+
readonly id: string;
|
|
417
|
+
/** The name of the lock and of the channel. */
|
|
418
|
+
readonly lockName: string;
|
|
419
|
+
private readonly group;
|
|
420
|
+
constructor(options: TabGroupOptions);
|
|
421
|
+
/** The role of this tab in the group. A collection has its own role too. */
|
|
422
|
+
get role(): TabRole;
|
|
423
|
+
/** True when this tab holds the lock of the group, or runs in the single mode. */
|
|
424
|
+
get isLeader(): boolean;
|
|
425
|
+
/** The names of the collections of the group in this tab. */
|
|
426
|
+
get collections(): string[];
|
|
310
427
|
/**
|
|
311
|
-
* This method
|
|
312
|
-
*
|
|
313
|
-
* the other tabs and to its outbox, and the capture of the storage ignores the local copy.
|
|
428
|
+
* This method gives a collection of the group. It adds the collection at its first use. When the
|
|
429
|
+
* group has the collection, the method gives it and ignores `options`.
|
|
314
430
|
*
|
|
315
|
-
* @
|
|
431
|
+
* @param options The options of a new collection. The default is the result of `open(name)`.
|
|
432
|
+
* @throws TypeError for a new collection without options, or with options of a wrong shape
|
|
433
|
+
* @throws Error after `close()`
|
|
316
434
|
*/
|
|
317
|
-
|
|
318
|
-
/** This method makes the `HybridStorage` of the single mode. The tab tries again after the backoff when it fails. */
|
|
319
|
-
private startSingle;
|
|
435
|
+
collection<T>(name: string, options?: TabCollectionOptions<T>): TabCollection<T>;
|
|
320
436
|
/**
|
|
321
|
-
* This method
|
|
322
|
-
* local copy until the tab leads.
|
|
437
|
+
* This method starts to send the role of this tab in the group to a listener at each change.
|
|
323
438
|
*
|
|
324
|
-
* @returns
|
|
325
|
-
|
|
326
|
-
private makeCandidate;
|
|
327
|
-
/**
|
|
328
|
-
* This method makes this tab the leader, or the single tab, with the storage of a candidate. The
|
|
329
|
-
* capture of the storage gets the batches of this tab that no leader acknowledged.
|
|
330
|
-
*/
|
|
331
|
-
private promote;
|
|
332
|
-
/** This method asks for the lock again, or tries the single mode again, after the backoff (roadmap CLI-67). */
|
|
333
|
-
private retryLater;
|
|
334
|
-
/**
|
|
335
|
-
* The local copy for the `HybridStorage` of the leader. Its `observe()` gives the changes of the
|
|
336
|
-
* local copy and the batches of the other tabs, so the capture queues both. It gives the changes
|
|
337
|
-
* of the local copy only when `gate` is open. Its `close()` does nothing: the application owns
|
|
338
|
-
* the local copy.
|
|
339
|
-
*/
|
|
340
|
-
private captureCopy;
|
|
341
|
-
/**
|
|
342
|
-
* This method gives a batch of another tab to the capture of the `HybridStorage` of the leader.
|
|
343
|
-
* The storage queues it. Its observers get it at once, and the coordinator ignores it there: the
|
|
344
|
-
* observers of the coordinator get it from the channel.
|
|
345
|
-
*/
|
|
346
|
-
private capture;
|
|
347
|
-
private setRole;
|
|
348
|
-
/** A status of the `HybridStorage` of this tab. The leader sends each new status to the followers. */
|
|
349
|
-
private onOwnStatus;
|
|
350
|
-
/** This method sends the last status of the leader, with its number. */
|
|
351
|
-
private postStatus;
|
|
352
|
-
/** A status of the leader. A tab that runs the sync keeps its own status. */
|
|
353
|
-
private onLeaderStatus;
|
|
354
|
-
/**
|
|
355
|
-
* A batch of the local copy of a follower. The writes of the coordinator itself (the batches of
|
|
356
|
-
* the other tabs in a copy of each tab) have the tag of the coordinator, and do not go out again.
|
|
357
|
-
*/
|
|
358
|
-
private onFollowerBatch;
|
|
359
|
-
/**
|
|
360
|
-
* A batch of the `HybridStorage` of the leader: a write of the application to the local copy,
|
|
361
|
-
* a write to the storage, or a change of the sync.
|
|
362
|
-
*/
|
|
363
|
-
private onLeaderBatch;
|
|
364
|
-
/**
|
|
365
|
-
* This method gives a batch of this tab to its observers and to the other tabs. A follower keeps
|
|
366
|
-
* it for the leader. A single tab whose setup failed keeps it for its next try.
|
|
367
|
-
*/
|
|
368
|
-
private share;
|
|
369
|
-
/** This method tells the leader the batches of this tab that no leader acknowledged. */
|
|
370
|
-
private hello;
|
|
371
|
-
/** @returns False when the message did not go out: no channel, or a value that the channel cannot clone */
|
|
372
|
-
private post;
|
|
373
|
-
private stopChannel;
|
|
374
|
-
private receive;
|
|
375
|
-
/**
|
|
376
|
-
* A batch of another tab. The leader captures it when the tab said hello to it. Each tab copies
|
|
377
|
-
* it one time.
|
|
378
|
-
*/
|
|
379
|
-
private onChanges;
|
|
380
|
-
/**
|
|
381
|
-
* The hello of another tab. The leader captures the batches that it did not capture, and then each
|
|
382
|
-
* batch of the tab after `seq`. It answers with its status. Each tab copies the batches that it
|
|
383
|
-
* did not see.
|
|
384
|
-
*/
|
|
385
|
-
private onHello;
|
|
386
|
-
/**
|
|
387
|
-
* This method copies a batch of another tab that this tab did not see: to the local copy of a
|
|
388
|
-
* tab, and then to the observers. The batches go in their order.
|
|
439
|
+
* @returns The function that stops the roles. A second use of it does nothing.
|
|
440
|
+
* @throws Error after `close()`
|
|
389
441
|
*/
|
|
390
|
-
|
|
442
|
+
onRole(listener: (role: TabRole) => void): () => void;
|
|
391
443
|
/**
|
|
392
|
-
* This method
|
|
393
|
-
*
|
|
394
|
-
* in a row go in one `setBatch`, and the deletes in a row in one `deleteBatch`.
|
|
444
|
+
* This method closes the group and each of its collections, as `TabCoordinator.close()` does.
|
|
445
|
+
* The leader closes each `HybridStorage`, and then it releases the lock.
|
|
395
446
|
*/
|
|
396
|
-
|
|
397
|
-
/** This method tells a tab that the queue store of the leader holds its batches up to `seq`. */
|
|
398
|
-
private acknowledge;
|
|
447
|
+
close(): Promise<void>;
|
|
399
448
|
}
|
|
400
449
|
//# sourceMappingURL=tab-coordinator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tab-coordinator.d.ts","sourceRoot":"","sources":["../../src/storage/tab-coordinator.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tab-coordinator.d.ts","sourceRoot":"","sources":["../../src/storage/tab-coordinator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4EG;AAEH,OAAO,KAAK,EACV,iBAAiB,EAGjB,eAAe,EAEhB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAyC,KAAK,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC3G,OAAO,EAAsC,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAE3G,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC9F,OAAO,KAAK,EAAa,UAAU,EAAE,MAAM,YAAY,CAAC;AAExD,+FAA+F;AAC/F,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAA;KAAE,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACxI;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAEpC,SAAS,EAAE,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;IACzC,KAAK,IAAI,IAAI,CAAC;CACf;AAED,6FAA6F;AAC7F,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,cAAc,CAAC;AAEjE;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,OAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAElE,yCAAyC;AACzC,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACtC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb,uGAAuG;IACvG,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAE3B;;;;;;;OAOG;IACH,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAC;IAEvB;;;OAGG;IACH,MAAM,EAAE,MAAM,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAEnC;;;;OAIG;IACH,MAAM,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,SAAS,CAAC,CAAC;IAEzD;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,GAAG,kBAAkB,CAAC;IAExC;;;OAGG;IACH,KAAK,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAElC;;;OAGG;IACH,OAAO,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAEnC;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,eAAe,CAAC;IAExB;;;;OAIG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IAEd;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;IAEtB;;;;OAIG;IACH,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAChC;AAED,kFAAkF;AAClF,MAAM,WAAW,eAAe;IAC9B,+GAA+G;IAC/G,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kHAAkH;IAClH,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,+HAA+H;IAC/H,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,kEAAkE;AAClE,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB;AAED,sEAAsE;AACtE,MAAM,WAAW,oBAAoB,CAAC,CAAC;IACrC,8EAA8E;IAC9E,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAE3B,qGAAqG;IACrG,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAC;IAEvB,sFAAsF;IACtF,MAAM,EAAE,MAAM,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAEnC;;;OAGG;IACH,MAAM,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,SAAS,CAAC,CAAC;IAEzD,kHAAkH;IAClH,QAAQ,CAAC,EAAE,OAAO,GAAG,kBAAkB,CAAC;CACzC;AAED,oDAAoD;AACpD,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;;OAIG;IAEH,IAAI,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,oBAAoB,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAErE,yGAAyG;IACzG,KAAK,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAElC,+HAA+H;IAC/H,OAAO,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAEnC;;;OAGG;IACH,KAAK,CAAC,EAAE,eAAe,CAAC;IAExB,uGAAuG;IACvG,KAAK,CAAC,EAAE,KAAK,CAAC;IAEd,0FAA0F;IAC1F,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;IAEtB,gIAAgI;IAChI,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,yGAAyG;IACzG,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,6FAA6F;IAC7F,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IACnD,qHAAqH;IACrH,OAAO,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC;IAClD,0FAA0F;IAC1F,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACtD,kGAAkG;IAClG,SAAS,IAAI,UAAU,GAAG,SAAS,CAAC;IACpC,wGAAwG;IACxG,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAC9D;AAsHD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,cAAc,CAAC,CAAC;IAC3B,gEAAgE;IAChE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAc;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAE/C,YAAY,OAAO,EAAE,qBAAqB,CAAC,CAAC,CAAC,EAkB5C;IAED,gCAAgC;IAChC,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,iFAAiF;IACjF,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED;;;;OAIG;IACH,IAAI,WAAW,IAAI,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS,CAE9C;IAED;;;;;;;;;;OAUG;IACH,OAAO,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAEhD;IAED;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI,CAEpD;IAED;;;;;;;;;;OAUG;IACH,SAAS,IAAI,UAAU,GAAG,SAAS,CAElC;IAED;;;;;;;;OAQG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,GAAG,MAAM,IAAI,CAE3D;IAED;;;;;;;;;;;OAWG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAErB;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,QAAQ;IACnB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAc;IAEpC,YAAY,OAAO,EAAE,eAAe,EAgBnC;IAED,4EAA4E;IAC5E,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,kFAAkF;IAClF,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,6DAA6D;IAC7D,IAAI,WAAW,IAAI,MAAM,EAAE,CAE1B;IAED;;;;;;;OAOG;IACH,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAE/E;IAED;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI,CAGpD;IAED;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAErB;CACF"}
|