@arcote.tech/arc-adapter-db-sqlite-wasm 0.7.14 → 0.7.15
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/dist/index.js +193 -152
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1485,11 +1485,11 @@ class EventWire {
|
|
|
1485
1485
|
reconnectTimeout;
|
|
1486
1486
|
syncRequested = false;
|
|
1487
1487
|
viewSubscriptions = new Map;
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
constructor(baseUrl) {
|
|
1488
|
+
enableEventSync;
|
|
1489
|
+
constructor(baseUrl, options) {
|
|
1491
1490
|
this.baseUrl = baseUrl;
|
|
1492
1491
|
this.instanceId = ++eventWireInstanceCounter;
|
|
1492
|
+
this.enableEventSync = options?.enableEventSync ?? true;
|
|
1493
1493
|
}
|
|
1494
1494
|
setScopeToken(scope, token) {
|
|
1495
1495
|
if (token === null) {
|
|
@@ -1535,9 +1535,11 @@ class EventWire {
|
|
|
1535
1535
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
1536
1536
|
this.state = "connected";
|
|
1537
1537
|
this.sendAllScopeTokens();
|
|
1538
|
-
this.
|
|
1538
|
+
if (this.enableEventSync) {
|
|
1539
|
+
this.requestSync();
|
|
1540
|
+
}
|
|
1539
1541
|
this.flushPendingEvents();
|
|
1540
|
-
this.
|
|
1542
|
+
this.sendAllViewSubscriptions();
|
|
1541
1543
|
} else {
|
|
1542
1544
|
console.log(`[EventWire] onopen called but ws is not OPEN, readyState:`, this.ws?.readyState);
|
|
1543
1545
|
}
|
|
@@ -1613,30 +1615,26 @@ class EventWire {
|
|
|
1613
1615
|
onSynced(callback) {
|
|
1614
1616
|
this.onSyncedCallback = callback;
|
|
1615
1617
|
}
|
|
1616
|
-
|
|
1617
|
-
const
|
|
1618
|
-
this.viewSubscriptions.set(
|
|
1618
|
+
subscribeView(element, scope, callbacks) {
|
|
1619
|
+
const key = `${scope}:${element}`;
|
|
1620
|
+
this.viewSubscriptions.set(key, callbacks);
|
|
1619
1621
|
if (this.state === "connected" && this.ws) {
|
|
1620
1622
|
this.ws.send(JSON.stringify({
|
|
1621
|
-
type: "subscribe-
|
|
1622
|
-
|
|
1623
|
-
descriptor,
|
|
1623
|
+
type: "subscribe-view",
|
|
1624
|
+
element,
|
|
1624
1625
|
scope
|
|
1625
1626
|
}));
|
|
1626
|
-
} else {
|
|
1627
|
-
this.pendingViewSubs.push({ subscriptionId, descriptor, scope });
|
|
1628
1627
|
}
|
|
1629
|
-
return subscriptionId;
|
|
1630
1628
|
}
|
|
1631
|
-
|
|
1632
|
-
this.viewSubscriptions.delete(
|
|
1629
|
+
unsubscribeView(element, scope) {
|
|
1630
|
+
this.viewSubscriptions.delete(`${scope}:${element}`);
|
|
1633
1631
|
if (this.state === "connected" && this.ws) {
|
|
1634
1632
|
this.ws.send(JSON.stringify({
|
|
1635
|
-
type: "unsubscribe-
|
|
1636
|
-
|
|
1633
|
+
type: "unsubscribe-view",
|
|
1634
|
+
element,
|
|
1635
|
+
scope
|
|
1637
1636
|
}));
|
|
1638
1637
|
}
|
|
1639
|
-
this.pendingViewSubs = this.pendingViewSubs.filter((s) => s.subscriptionId !== subscriptionId);
|
|
1640
1638
|
}
|
|
1641
1639
|
getState() {
|
|
1642
1640
|
return this.state;
|
|
@@ -1669,10 +1667,17 @@ class EventWire {
|
|
|
1669
1667
|
this.lastHostEventId = message.lastHostEventId;
|
|
1670
1668
|
}
|
|
1671
1669
|
break;
|
|
1672
|
-
case "
|
|
1673
|
-
const
|
|
1674
|
-
if (
|
|
1675
|
-
|
|
1670
|
+
case "view-snapshot": {
|
|
1671
|
+
const sub = this.viewSubscriptions.get(`${message.scope}:${message.element}`);
|
|
1672
|
+
if (sub) {
|
|
1673
|
+
sub.onSnapshot(message.items ?? []);
|
|
1674
|
+
}
|
|
1675
|
+
break;
|
|
1676
|
+
}
|
|
1677
|
+
case "view-changes": {
|
|
1678
|
+
const sub = this.viewSubscriptions.get(`${message.scope}:${message.element}`);
|
|
1679
|
+
if (sub && Array.isArray(message.changes)) {
|
|
1680
|
+
sub.onChanges(message.changes);
|
|
1676
1681
|
}
|
|
1677
1682
|
break;
|
|
1678
1683
|
}
|
|
@@ -1700,18 +1705,19 @@ class EventWire {
|
|
|
1700
1705
|
this.pendingEvents = [];
|
|
1701
1706
|
}
|
|
1702
1707
|
}
|
|
1703
|
-
|
|
1708
|
+
sendAllViewSubscriptions() {
|
|
1704
1709
|
if (!this.ws || this.state !== "connected")
|
|
1705
1710
|
return;
|
|
1706
|
-
for (const
|
|
1711
|
+
for (const key of this.viewSubscriptions.keys()) {
|
|
1712
|
+
const sepIdx = key.indexOf(":");
|
|
1713
|
+
const scope = key.slice(0, sepIdx);
|
|
1714
|
+
const element = key.slice(sepIdx + 1);
|
|
1707
1715
|
this.ws.send(JSON.stringify({
|
|
1708
|
-
type: "subscribe-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
scope: sub.scope
|
|
1716
|
+
type: "subscribe-view",
|
|
1717
|
+
element,
|
|
1718
|
+
scope
|
|
1712
1719
|
}));
|
|
1713
1720
|
}
|
|
1714
|
-
this.pendingViewSubs = [];
|
|
1715
1721
|
}
|
|
1716
1722
|
scheduleReconnect() {
|
|
1717
1723
|
if (this.reconnectTimeout)
|
|
@@ -1733,12 +1739,19 @@ class LocalEventPublisher {
|
|
|
1733
1739
|
views = [];
|
|
1734
1740
|
syncCallback;
|
|
1735
1741
|
subscribers = new Map;
|
|
1742
|
+
viewChangesCallbacks = new Set;
|
|
1736
1743
|
constructor(dataStorage) {
|
|
1737
1744
|
this.dataStorage = dataStorage;
|
|
1738
1745
|
}
|
|
1739
1746
|
onPublish(callback) {
|
|
1740
1747
|
this.syncCallback = callback;
|
|
1741
1748
|
}
|
|
1749
|
+
onViewChanges(callback) {
|
|
1750
|
+
this.viewChangesCallbacks.add(callback);
|
|
1751
|
+
return () => {
|
|
1752
|
+
this.viewChangesCallbacks.delete(callback);
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1742
1755
|
registerViews(views) {
|
|
1743
1756
|
this.views = views;
|
|
1744
1757
|
}
|
|
@@ -1806,7 +1819,19 @@ class LocalEventPublisher {
|
|
|
1806
1819
|
});
|
|
1807
1820
|
const viewChanges = await this.collectViewChanges(event);
|
|
1808
1821
|
allChanges.push(...viewChanges);
|
|
1809
|
-
|
|
1822
|
+
const viewStoreNames = new Set(viewChanges.map((c) => c.store));
|
|
1823
|
+
const committed = await this.dataStorage.commitChanges(allChanges, {
|
|
1824
|
+
captureRowsFor: viewStoreNames
|
|
1825
|
+
});
|
|
1826
|
+
if (committed.length > 0 && this.viewChangesCallbacks.size > 0) {
|
|
1827
|
+
for (const callback of this.viewChangesCallbacks) {
|
|
1828
|
+
try {
|
|
1829
|
+
callback(committed);
|
|
1830
|
+
} catch (error) {
|
|
1831
|
+
console.error(`[EventPublisher] onViewChanges callback error:`, error);
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1810
1835
|
await this.notifySubscribers(event);
|
|
1811
1836
|
if (this.syncCallback) {
|
|
1812
1837
|
this.syncCallback(event);
|
|
@@ -2446,8 +2471,9 @@ class ArcObject extends ArcAbstract {
|
|
|
2446
2471
|
}
|
|
2447
2472
|
}
|
|
2448
2473
|
class DataStorage {
|
|
2449
|
-
async commitChanges(changes) {
|
|
2474
|
+
async commitChanges(changes, _options) {
|
|
2450
2475
|
await Promise.all(changes.map(({ store, changes: changes2 }) => this.getStore(store).applyChanges(changes2)));
|
|
2476
|
+
return [];
|
|
2451
2477
|
}
|
|
2452
2478
|
}
|
|
2453
2479
|
|
|
@@ -3686,12 +3712,23 @@ class MasterStoreState extends StoreState {
|
|
|
3686
3712
|
constructor(storeName, dataStorage, deserialize) {
|
|
3687
3713
|
super(storeName, dataStorage, deserialize);
|
|
3688
3714
|
}
|
|
3689
|
-
async
|
|
3715
|
+
async readExisting(transaction, id2, transactionCache) {
|
|
3716
|
+
const cacheKey = `${this.storeName}:${id2}`;
|
|
3717
|
+
if (transactionCache && transactionCache.has(cacheKey)) {
|
|
3718
|
+
return transactionCache.get(cacheKey);
|
|
3719
|
+
}
|
|
3720
|
+
return transaction.find(this.storeName, { where: { _id: id2 } }).then((results) => results[0]);
|
|
3721
|
+
}
|
|
3722
|
+
async applyChangeAndReturnEvent(transaction, change, transactionCache, options) {
|
|
3690
3723
|
if (change.type === "set") {
|
|
3724
|
+
let existing;
|
|
3725
|
+
if (options?.captureRows) {
|
|
3726
|
+
existing = await this.readExisting(transaction, change.data._id, transactionCache);
|
|
3727
|
+
}
|
|
3691
3728
|
await transaction.set(this.storeName, change.data);
|
|
3692
3729
|
const item = this.deserialize ? this.deserialize(change.data) : change.data;
|
|
3693
3730
|
if (transactionCache) {
|
|
3694
|
-
transactionCache.set(change.data._id
|
|
3731
|
+
transactionCache.set(`${this.storeName}:${change.data._id}`, item);
|
|
3695
3732
|
}
|
|
3696
3733
|
return {
|
|
3697
3734
|
from: null,
|
|
@@ -3700,11 +3737,20 @@ class MasterStoreState extends StoreState {
|
|
|
3700
3737
|
type: "set",
|
|
3701
3738
|
item: change.data,
|
|
3702
3739
|
id: change.data._id
|
|
3703
|
-
}
|
|
3740
|
+
},
|
|
3741
|
+
oldRow: existing ?? null,
|
|
3742
|
+
newRow: change.data
|
|
3704
3743
|
};
|
|
3705
3744
|
}
|
|
3706
3745
|
if (change.type === "delete") {
|
|
3746
|
+
let existing;
|
|
3747
|
+
if (options?.captureRows) {
|
|
3748
|
+
existing = await this.readExisting(transaction, change.id, transactionCache);
|
|
3749
|
+
}
|
|
3707
3750
|
await transaction.remove(this.storeName, change.id);
|
|
3751
|
+
if (transactionCache) {
|
|
3752
|
+
transactionCache.delete(`${this.storeName}:${change.id}`);
|
|
3753
|
+
}
|
|
3708
3754
|
return {
|
|
3709
3755
|
from: null,
|
|
3710
3756
|
to: null,
|
|
@@ -3712,21 +3758,18 @@ class MasterStoreState extends StoreState {
|
|
|
3712
3758
|
type: "delete",
|
|
3713
3759
|
item: null,
|
|
3714
3760
|
id: change.id
|
|
3715
|
-
}
|
|
3761
|
+
},
|
|
3762
|
+
oldRow: existing ?? null,
|
|
3763
|
+
newRow: null
|
|
3716
3764
|
};
|
|
3717
3765
|
}
|
|
3718
3766
|
if (change.type === "modify") {
|
|
3719
|
-
|
|
3720
|
-
if (transactionCache && transactionCache.has(change.id)) {
|
|
3721
|
-
existing = transactionCache.get(change.id);
|
|
3722
|
-
} else {
|
|
3723
|
-
existing = await transaction.find(this.storeName, { where: { _id: change.id } }).then((results) => results[0]);
|
|
3724
|
-
}
|
|
3767
|
+
const existing = await this.readExisting(transaction, change.id, transactionCache);
|
|
3725
3768
|
const updated = existing ? deepMerge(existing, change.data) : { _id: change.id, ...change.data };
|
|
3726
3769
|
await transaction.set(this.storeName, updated);
|
|
3727
3770
|
const item = this.deserialize ? this.deserialize(updated) : updated;
|
|
3728
3771
|
if (transactionCache) {
|
|
3729
|
-
transactionCache.set(change.id
|
|
3772
|
+
transactionCache.set(`${this.storeName}:${change.id}`, item);
|
|
3730
3773
|
}
|
|
3731
3774
|
return {
|
|
3732
3775
|
from: null,
|
|
@@ -3735,21 +3778,18 @@ class MasterStoreState extends StoreState {
|
|
|
3735
3778
|
type: "set",
|
|
3736
3779
|
item,
|
|
3737
3780
|
id: change.id
|
|
3738
|
-
}
|
|
3781
|
+
},
|
|
3782
|
+
oldRow: existing ?? null,
|
|
3783
|
+
newRow: updated
|
|
3739
3784
|
};
|
|
3740
3785
|
}
|
|
3741
3786
|
if (change.type === "mutate") {
|
|
3742
|
-
|
|
3743
|
-
if (transactionCache && transactionCache.has(change.id)) {
|
|
3744
|
-
existing = transactionCache.get(change.id);
|
|
3745
|
-
} else {
|
|
3746
|
-
existing = await transaction.find(this.storeName, { where: { _id: change.id } }).then((results) => results[0]);
|
|
3747
|
-
}
|
|
3787
|
+
const existing = await this.readExisting(transaction, change.id, transactionCache);
|
|
3748
3788
|
const updated = apply(existing || {}, change.patches);
|
|
3749
3789
|
await transaction.set(this.storeName, updated);
|
|
3750
3790
|
const item = this.deserialize ? this.deserialize(updated) : updated;
|
|
3751
3791
|
if (transactionCache) {
|
|
3752
|
-
transactionCache.set(change.id
|
|
3792
|
+
transactionCache.set(`${this.storeName}:${change.id}`, item);
|
|
3753
3793
|
}
|
|
3754
3794
|
return {
|
|
3755
3795
|
from: null,
|
|
@@ -3758,7 +3798,9 @@ class MasterStoreState extends StoreState {
|
|
|
3758
3798
|
type: "set",
|
|
3759
3799
|
item,
|
|
3760
3800
|
id: change.id
|
|
3761
|
-
}
|
|
3801
|
+
},
|
|
3802
|
+
oldRow: existing ?? null,
|
|
3803
|
+
newRow: updated
|
|
3762
3804
|
};
|
|
3763
3805
|
}
|
|
3764
3806
|
throw new Error("Unknown change type");
|
|
@@ -3836,17 +3878,22 @@ class MasterDataStorage extends DataStorage {
|
|
|
3836
3878
|
applySerializedChanges(changes) {
|
|
3837
3879
|
return Promise.all(changes.map(({ store, changes: changes2 }) => this.getStore(store).applySerializedChanges(changes2)));
|
|
3838
3880
|
}
|
|
3839
|
-
async commitChanges(changes) {
|
|
3881
|
+
async commitChanges(changes, options) {
|
|
3840
3882
|
const transaction = await this.getReadWriteTransaction();
|
|
3841
3883
|
const transactionCache = new Map;
|
|
3842
3884
|
const eventsByStore = new Map;
|
|
3885
|
+
const committed = [];
|
|
3843
3886
|
for (const { store, changes: storeChanges } of changes) {
|
|
3844
3887
|
const storeState = this.getStore(store);
|
|
3845
3888
|
const storeEvents = [];
|
|
3889
|
+
const capture = options?.captureRowsFor?.has(store) ?? false;
|
|
3846
3890
|
for (const change of storeChanges) {
|
|
3847
|
-
const { event: event3 } = await storeState.applyChangeAndReturnEvent(transaction, change, transactionCache);
|
|
3891
|
+
const { event: event3, oldRow, newRow } = await storeState.applyChangeAndReturnEvent(transaction, change, transactionCache, { captureRows: capture });
|
|
3848
3892
|
if (event3)
|
|
3849
3893
|
storeEvents.push(event3);
|
|
3894
|
+
if (capture) {
|
|
3895
|
+
committed.push({ store, id: event3.id, oldRow, newRow });
|
|
3896
|
+
}
|
|
3850
3897
|
}
|
|
3851
3898
|
if (storeEvents.length > 0) {
|
|
3852
3899
|
eventsByStore.set(store, storeEvents);
|
|
@@ -3857,6 +3904,7 @@ class MasterDataStorage extends DataStorage {
|
|
|
3857
3904
|
const storeState = this.getStore(store);
|
|
3858
3905
|
storeState.notifyListenersPublic(events);
|
|
3859
3906
|
}
|
|
3907
|
+
return committed;
|
|
3860
3908
|
}
|
|
3861
3909
|
fork() {
|
|
3862
3910
|
return new ForkedDataStorage(this);
|
|
@@ -3971,8 +4019,8 @@ class ObservableDataStorage {
|
|
|
3971
4019
|
getReadWriteTransaction() {
|
|
3972
4020
|
return this.source.getReadWriteTransaction();
|
|
3973
4021
|
}
|
|
3974
|
-
commitChanges(changes) {
|
|
3975
|
-
return this.source.commitChanges(changes);
|
|
4022
|
+
commitChanges(changes, options) {
|
|
4023
|
+
return this.source.commitChanges(changes, options);
|
|
3976
4024
|
}
|
|
3977
4025
|
trackQuery(storeName, options, result, listener4) {
|
|
3978
4026
|
const key = this.getQueryKey(storeName, options);
|
|
@@ -4216,13 +4264,6 @@ class ScopedModel {
|
|
|
4216
4264
|
}
|
|
4217
4265
|
return wire.query(viewName, options, this.getAuth());
|
|
4218
4266
|
}
|
|
4219
|
-
subscribeQuery(descriptor, callback) {
|
|
4220
|
-
const wire = this.parent.getAdapters().eventWire;
|
|
4221
|
-
if (!wire) {
|
|
4222
|
-
throw new Error(`Cannot subscribe to query: no eventWire available.`);
|
|
4223
|
-
}
|
|
4224
|
-
return wire.subscribeQuery(descriptor, callback, this.scopeName);
|
|
4225
|
-
}
|
|
4226
4267
|
get query() {
|
|
4227
4268
|
return buildContextAccessor(this.context, this.scopedAdapters, "queryContext", (descriptor) => descriptor);
|
|
4228
4269
|
}
|
|
@@ -4278,120 +4319,107 @@ class Model {
|
|
|
4278
4319
|
return s;
|
|
4279
4320
|
}
|
|
4280
4321
|
}
|
|
4322
|
+
var DEFAULT_SCOPE = "default";
|
|
4323
|
+
|
|
4281
4324
|
class StreamingQueryCache {
|
|
4282
4325
|
stores = new Map;
|
|
4283
4326
|
views = [];
|
|
4284
4327
|
activeStreams = new Map;
|
|
4285
4328
|
pendingUnsubscribes = new Map;
|
|
4286
|
-
streamScopes = new Map;
|
|
4287
4329
|
static UNSUBSCRIBE_DELAY_MS = 5000;
|
|
4330
|
+
storeKey(viewName, scope) {
|
|
4331
|
+
return `${scope ?? DEFAULT_SCOPE}:${viewName}`;
|
|
4332
|
+
}
|
|
4288
4333
|
registerViews(views) {
|
|
4289
4334
|
this.views = views;
|
|
4290
|
-
for (const view3 of views) {
|
|
4291
|
-
if (!this.stores.has(view3.name)) {
|
|
4292
|
-
this.stores.set(view3.name, new StreamingStore);
|
|
4293
|
-
}
|
|
4294
|
-
}
|
|
4295
4335
|
}
|
|
4296
|
-
getStore(viewName) {
|
|
4297
|
-
|
|
4298
|
-
|
|
4336
|
+
getStore(viewName, scope) {
|
|
4337
|
+
const key = this.storeKey(viewName, scope);
|
|
4338
|
+
if (!this.stores.has(key)) {
|
|
4339
|
+
this.stores.set(key, new StreamingStore);
|
|
4299
4340
|
}
|
|
4300
|
-
return this.stores.get(
|
|
4341
|
+
return this.stores.get(key);
|
|
4301
4342
|
}
|
|
4302
|
-
hasData(viewName) {
|
|
4303
|
-
const store = this.stores.get(viewName);
|
|
4343
|
+
hasData(viewName, scope) {
|
|
4344
|
+
const store = this.stores.get(this.storeKey(viewName, scope));
|
|
4304
4345
|
return store ? store.hasData() : false;
|
|
4305
4346
|
}
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
}
|
|
4309
|
-
registerStream(viewName, createStream) {
|
|
4310
|
-
const pending = this.pendingUnsubscribes.get(viewName);
|
|
4347
|
+
registerStream(key, createStream) {
|
|
4348
|
+
const pending = this.pendingUnsubscribes.get(key);
|
|
4311
4349
|
if (pending) {
|
|
4312
4350
|
clearTimeout(pending);
|
|
4313
|
-
this.pendingUnsubscribes.delete(
|
|
4351
|
+
this.pendingUnsubscribes.delete(key);
|
|
4314
4352
|
}
|
|
4315
|
-
const existing = this.activeStreams.get(
|
|
4353
|
+
const existing = this.activeStreams.get(key);
|
|
4316
4354
|
if (existing) {
|
|
4317
4355
|
existing.refCount++;
|
|
4318
4356
|
return {
|
|
4319
|
-
unsubscribe: () => this.unregisterStream(
|
|
4357
|
+
unsubscribe: () => this.unregisterStream(key),
|
|
4320
4358
|
wasReused: true
|
|
4321
4359
|
};
|
|
4322
4360
|
}
|
|
4323
4361
|
const streamConn = createStream();
|
|
4324
|
-
this.activeStreams.set(
|
|
4362
|
+
this.activeStreams.set(key, {
|
|
4325
4363
|
unsubscribe: streamConn.unsubscribe,
|
|
4326
4364
|
refCount: 1
|
|
4327
4365
|
});
|
|
4328
4366
|
return {
|
|
4329
|
-
unsubscribe: () => this.unregisterStream(
|
|
4367
|
+
unsubscribe: () => this.unregisterStream(key),
|
|
4330
4368
|
wasReused: false
|
|
4331
4369
|
};
|
|
4332
4370
|
}
|
|
4333
|
-
unregisterStream(
|
|
4334
|
-
const stream = this.activeStreams.get(
|
|
4371
|
+
unregisterStream(key) {
|
|
4372
|
+
const stream = this.activeStreams.get(key);
|
|
4335
4373
|
if (!stream)
|
|
4336
4374
|
return;
|
|
4337
4375
|
stream.refCount--;
|
|
4338
4376
|
if (stream.refCount <= 0) {
|
|
4339
4377
|
const timeout = setTimeout(() => {
|
|
4340
|
-
this.pendingUnsubscribes.delete(
|
|
4341
|
-
const current2 = this.activeStreams.get(
|
|
4378
|
+
this.pendingUnsubscribes.delete(key);
|
|
4379
|
+
const current2 = this.activeStreams.get(key);
|
|
4342
4380
|
if (current2 && current2.refCount <= 0) {
|
|
4343
4381
|
current2.unsubscribe();
|
|
4344
|
-
this.activeStreams.delete(
|
|
4345
|
-
this.streamScopes.delete(viewName);
|
|
4382
|
+
this.activeStreams.delete(key);
|
|
4346
4383
|
}
|
|
4347
4384
|
}, StreamingQueryCache.UNSUBSCRIBE_DELAY_MS);
|
|
4348
|
-
this.pendingUnsubscribes.set(
|
|
4385
|
+
this.pendingUnsubscribes.set(key, timeout);
|
|
4349
4386
|
}
|
|
4350
4387
|
}
|
|
4351
|
-
|
|
4352
|
-
const key =
|
|
4353
|
-
if (scope)
|
|
4354
|
-
this.streamScopes.set(key, scope);
|
|
4388
|
+
subscribeView(viewName, eventWire, scope) {
|
|
4389
|
+
const key = this.storeKey(viewName, scope);
|
|
4355
4390
|
const { unsubscribe } = this.registerStream(key, () => {
|
|
4356
|
-
const
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4391
|
+
const store = this.stores.get(key) ?? new StreamingStore;
|
|
4392
|
+
this.stores.set(key, store);
|
|
4393
|
+
eventWire.subscribeView(viewName, scope ?? DEFAULT_SCOPE, {
|
|
4394
|
+
onSnapshot: (items) => store.setAll(items),
|
|
4395
|
+
onChanges: (changes) => store.applyChanges(changes)
|
|
4396
|
+
});
|
|
4397
|
+
return {
|
|
4398
|
+
unsubscribe: () => eventWire.unsubscribeView(viewName, scope ?? DEFAULT_SCOPE)
|
|
4399
|
+
};
|
|
4360
4400
|
});
|
|
4361
4401
|
return unsubscribe;
|
|
4362
4402
|
}
|
|
4363
4403
|
invalidateScope(scope) {
|
|
4364
|
-
|
|
4365
|
-
|
|
4404
|
+
const prefix = `${scope}:`;
|
|
4405
|
+
for (const [key, timeout] of this.pendingUnsubscribes) {
|
|
4406
|
+
if (!key.startsWith(prefix))
|
|
4366
4407
|
continue;
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
clearTimeout(pending);
|
|
4370
|
-
this.pendingUnsubscribes.delete(viewName);
|
|
4371
|
-
}
|
|
4372
|
-
const stream = this.activeStreams.get(viewName);
|
|
4373
|
-
if (stream) {
|
|
4374
|
-
try {
|
|
4375
|
-
stream.unsubscribe();
|
|
4376
|
-
} catch {}
|
|
4377
|
-
this.activeStreams.delete(viewName);
|
|
4378
|
-
}
|
|
4379
|
-
this.streamScopes.delete(viewName);
|
|
4380
|
-
const store = this.stores.get(viewName);
|
|
4381
|
-
if (store)
|
|
4382
|
-
store.clear();
|
|
4408
|
+
clearTimeout(timeout);
|
|
4409
|
+
this.pendingUnsubscribes.delete(key);
|
|
4383
4410
|
}
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
}
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4411
|
+
for (const [key, stream] of this.activeStreams) {
|
|
4412
|
+
if (!key.startsWith(prefix))
|
|
4413
|
+
continue;
|
|
4414
|
+
try {
|
|
4415
|
+
stream.unsubscribe();
|
|
4416
|
+
} catch {}
|
|
4417
|
+
this.activeStreams.delete(key);
|
|
4418
|
+
}
|
|
4419
|
+
for (const [key, store] of this.stores) {
|
|
4420
|
+
if (!key.startsWith(prefix))
|
|
4421
|
+
continue;
|
|
4422
|
+
store.clear();
|
|
4395
4423
|
}
|
|
4396
4424
|
}
|
|
4397
4425
|
async applyEvent(event3) {
|
|
@@ -4400,28 +4428,30 @@ class StreamingQueryCache {
|
|
|
4400
4428
|
const handler = handlers[event3.type];
|
|
4401
4429
|
if (!handler)
|
|
4402
4430
|
continue;
|
|
4403
|
-
const
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4431
|
+
const suffix = `:${view3.name}`;
|
|
4432
|
+
for (const [key, store] of this.stores) {
|
|
4433
|
+
if (!key.endsWith(suffix))
|
|
4434
|
+
continue;
|
|
4435
|
+
const ctx = {
|
|
4436
|
+
set: async (id3, data) => {
|
|
4437
|
+
store.set(String(id3), { _id: String(id3), ...data });
|
|
4438
|
+
},
|
|
4439
|
+
modify: async (id3, data) => {
|
|
4440
|
+
store.modify(String(id3), data);
|
|
4441
|
+
},
|
|
4442
|
+
remove: async (id3) => {
|
|
4443
|
+
store.remove(String(id3));
|
|
4444
|
+
},
|
|
4445
|
+
find: async (options) => {
|
|
4446
|
+
return store.find(options);
|
|
4447
|
+
},
|
|
4448
|
+
findOne: async (where) => {
|
|
4449
|
+
return store.findOne(where);
|
|
4450
|
+
},
|
|
4451
|
+
$auth: {}
|
|
4452
|
+
};
|
|
4453
|
+
await handler(ctx, event3);
|
|
4454
|
+
}
|
|
4425
4455
|
}
|
|
4426
4456
|
}
|
|
4427
4457
|
clear() {
|
|
@@ -4429,7 +4459,6 @@ class StreamingQueryCache {
|
|
|
4429
4459
|
stream.unsubscribe();
|
|
4430
4460
|
}
|
|
4431
4461
|
this.activeStreams.clear();
|
|
4432
|
-
this.streamScopes.clear();
|
|
4433
4462
|
for (const timeout of this.pendingUnsubscribes.values()) {
|
|
4434
4463
|
clearTimeout(timeout);
|
|
4435
4464
|
}
|
|
@@ -4455,6 +4484,18 @@ class StreamingStore {
|
|
|
4455
4484
|
}
|
|
4456
4485
|
this.notifyListeners(null);
|
|
4457
4486
|
}
|
|
4487
|
+
applyChanges(events) {
|
|
4488
|
+
if (events.length === 0)
|
|
4489
|
+
return;
|
|
4490
|
+
for (const event3 of events) {
|
|
4491
|
+
if (event3.type === "set" && event3.item) {
|
|
4492
|
+
this.data.set(event3.id, event3.item);
|
|
4493
|
+
} else if (event3.type === "delete") {
|
|
4494
|
+
this.data.delete(event3.id);
|
|
4495
|
+
}
|
|
4496
|
+
}
|
|
4497
|
+
this.notifyListeners(events);
|
|
4498
|
+
}
|
|
4458
4499
|
set(id3, item) {
|
|
4459
4500
|
this.data.set(id3, item);
|
|
4460
4501
|
this.notifyListeners([{ type: "set", id: id3, item }]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcote.tech/arc-adapter-db-sqlite-wasm",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dev": "bun build ./src/index.ts ./src/worker.ts --outdir ./dist --target browser --format esm --watch"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"@arcote.tech/arc": "^0.7.
|
|
42
|
+
"@arcote.tech/arc": "^0.7.15",
|
|
43
43
|
"@sqlite.org/sqlite-wasm": "^3.46.0-build1"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|