@electric-sql/client 1.0.10 → 1.0.11
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/cjs/index.cjs +338 -24
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +90 -5
- package/dist/index.browser.mjs +3 -3
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.ts +90 -5
- package/dist/index.legacy-esm.js +325 -24
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +337 -24
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +203 -6
- package/src/constants.ts +12 -0
- package/src/fetch.ts +19 -1
- package/src/helpers.ts +34 -1
- package/src/index.ts +5 -1
- package/src/shape.ts +104 -14
- package/src/snapshot-tracker.ts +88 -0
- package/src/types.ts +40 -6
package/dist/index.legacy-esm.js
CHANGED
|
@@ -37,6 +37,14 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
|
|
|
37
37
|
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
38
38
|
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
39
39
|
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
40
|
+
var __privateWrapper = (obj, member, setter, getter) => ({
|
|
41
|
+
set _(value) {
|
|
42
|
+
__privateSet(obj, member, value, setter);
|
|
43
|
+
},
|
|
44
|
+
get _() {
|
|
45
|
+
return __privateGet(obj, member, getter);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
40
48
|
|
|
41
49
|
// src/error.ts
|
|
42
50
|
var FetchError = class _FetchError extends Error {
|
|
@@ -256,6 +264,13 @@ function getOffset(message) {
|
|
|
256
264
|
}
|
|
257
265
|
return `${lsn}_0`;
|
|
258
266
|
}
|
|
267
|
+
function isVisibleInSnapshot(txid, snapshot) {
|
|
268
|
+
const xid = BigInt(txid);
|
|
269
|
+
const xmin = BigInt(snapshot.xmin);
|
|
270
|
+
const xmax = BigInt(snapshot.xmax);
|
|
271
|
+
const xip = snapshot.xip_list.map(BigInt);
|
|
272
|
+
return xid < xmin || xid < xmax && !xip.includes(xid);
|
|
273
|
+
}
|
|
259
274
|
|
|
260
275
|
// src/constants.ts
|
|
261
276
|
var LIVE_CACHE_BUSTER_HEADER = `electric-cursor`;
|
|
@@ -276,12 +291,24 @@ var WHERE_PARAMS_PARAM = `params`;
|
|
|
276
291
|
var EXPERIMENTAL_LIVE_SSE_QUERY_PARAM = `experimental_live_sse`;
|
|
277
292
|
var FORCE_DISCONNECT_AND_REFRESH = `force-disconnect-and-refresh`;
|
|
278
293
|
var PAUSE_STREAM = `pause-stream`;
|
|
294
|
+
var LOG_MODE_QUERY_PARAM = `log`;
|
|
295
|
+
var SUBSET_PARAM_WHERE = `subset__where`;
|
|
296
|
+
var SUBSET_PARAM_LIMIT = `subset__limit`;
|
|
297
|
+
var SUBSET_PARAM_OFFSET = `subset__offset`;
|
|
298
|
+
var SUBSET_PARAM_ORDER_BY = `subset__order_by`;
|
|
299
|
+
var SUBSET_PARAM_WHERE_PARAMS = `subset__params`;
|
|
279
300
|
var ELECTRIC_PROTOCOL_QUERY_PARAMS = [
|
|
280
301
|
LIVE_QUERY_PARAM,
|
|
281
302
|
SHAPE_HANDLE_QUERY_PARAM,
|
|
282
303
|
OFFSET_QUERY_PARAM,
|
|
283
304
|
LIVE_CACHE_BUSTER_QUERY_PARAM,
|
|
284
|
-
EXPIRED_HANDLE_QUERY_PARAM
|
|
305
|
+
EXPIRED_HANDLE_QUERY_PARAM,
|
|
306
|
+
LOG_MODE_QUERY_PARAM,
|
|
307
|
+
SUBSET_PARAM_WHERE,
|
|
308
|
+
SUBSET_PARAM_LIMIT,
|
|
309
|
+
SUBSET_PARAM_OFFSET,
|
|
310
|
+
SUBSET_PARAM_ORDER_BY,
|
|
311
|
+
SUBSET_PARAM_WHERE_PARAMS
|
|
285
312
|
];
|
|
286
313
|
|
|
287
314
|
// src/fetch.ts
|
|
@@ -392,10 +419,20 @@ function createFetchWithResponseHeadersCheck(fetchClient) {
|
|
|
392
419
|
const headers = response.headers;
|
|
393
420
|
const missingHeaders = [];
|
|
394
421
|
const addMissingHeaders = (requiredHeaders) => missingHeaders.push(...requiredHeaders.filter((h) => !headers.has(h)));
|
|
395
|
-
addMissingHeaders(requiredElectricResponseHeaders);
|
|
396
422
|
const input = args[0];
|
|
397
423
|
const urlString = input.toString();
|
|
398
424
|
const url = new URL(urlString);
|
|
425
|
+
const isSnapshotRequest = [
|
|
426
|
+
SUBSET_PARAM_WHERE,
|
|
427
|
+
SUBSET_PARAM_WHERE_PARAMS,
|
|
428
|
+
SUBSET_PARAM_LIMIT,
|
|
429
|
+
SUBSET_PARAM_OFFSET,
|
|
430
|
+
SUBSET_PARAM_ORDER_BY
|
|
431
|
+
].some((p) => url.searchParams.has(p));
|
|
432
|
+
if (isSnapshotRequest) {
|
|
433
|
+
return response;
|
|
434
|
+
}
|
|
435
|
+
addMissingHeaders(requiredElectricResponseHeaders);
|
|
399
436
|
if (url.searchParams.get(LIVE_QUERY_PARAM) === `true`) {
|
|
400
437
|
addMissingHeaders(requiredLiveResponseHeaders);
|
|
401
438
|
}
|
|
@@ -565,6 +602,68 @@ var ExpiredShapesCache = class {
|
|
|
565
602
|
};
|
|
566
603
|
var expiredShapesCache = new ExpiredShapesCache();
|
|
567
604
|
|
|
605
|
+
// src/snapshot-tracker.ts
|
|
606
|
+
var SnapshotTracker = class {
|
|
607
|
+
constructor() {
|
|
608
|
+
this.activeSnapshots = /* @__PURE__ */ new Map();
|
|
609
|
+
this.xmaxSnapshots = /* @__PURE__ */ new Map();
|
|
610
|
+
this.snapshotsByDatabaseLsn = /* @__PURE__ */ new Map();
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Add a new snapshot for tracking
|
|
614
|
+
*/
|
|
615
|
+
addSnapshot(metadata, keys) {
|
|
616
|
+
var _a, _b, _c, _d;
|
|
617
|
+
this.activeSnapshots.set(metadata.snapshot_mark, {
|
|
618
|
+
xmin: BigInt(metadata.xmin),
|
|
619
|
+
xmax: BigInt(metadata.xmax),
|
|
620
|
+
xip_list: metadata.xip_list.map(BigInt),
|
|
621
|
+
keys
|
|
622
|
+
});
|
|
623
|
+
const xmaxSet = (_b = (_a = this.xmaxSnapshots.get(BigInt(metadata.xmax))) == null ? void 0 : _a.add(metadata.snapshot_mark)) != null ? _b : /* @__PURE__ */ new Set([metadata.snapshot_mark]);
|
|
624
|
+
this.xmaxSnapshots.set(BigInt(metadata.xmax), xmaxSet);
|
|
625
|
+
const databaseLsnSet = (_d = (_c = this.snapshotsByDatabaseLsn.get(BigInt(metadata.database_lsn))) == null ? void 0 : _c.add(metadata.snapshot_mark)) != null ? _d : /* @__PURE__ */ new Set([metadata.snapshot_mark]);
|
|
626
|
+
this.snapshotsByDatabaseLsn.set(
|
|
627
|
+
BigInt(metadata.database_lsn),
|
|
628
|
+
databaseLsnSet
|
|
629
|
+
);
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Remove a snapshot from tracking
|
|
633
|
+
*/
|
|
634
|
+
removeSnapshot(snapshotMark) {
|
|
635
|
+
this.activeSnapshots.delete(snapshotMark);
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Check if a change message should be filtered because its already in an active snapshot
|
|
639
|
+
* Returns true if the message should be filtered out (not processed)
|
|
640
|
+
*/
|
|
641
|
+
shouldRejectMessage(message) {
|
|
642
|
+
const txids = message.headers.txids || [];
|
|
643
|
+
if (txids.length === 0) return false;
|
|
644
|
+
const xid = Math.max(...txids);
|
|
645
|
+
for (const [xmax, snapshots] of this.xmaxSnapshots.entries()) {
|
|
646
|
+
if (xid >= xmax) {
|
|
647
|
+
for (const snapshot of snapshots) {
|
|
648
|
+
this.removeSnapshot(snapshot);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
return [...this.activeSnapshots.values()].some(
|
|
653
|
+
(x) => x.keys.has(message.key) && isVisibleInSnapshot(xid, x)
|
|
654
|
+
);
|
|
655
|
+
}
|
|
656
|
+
lastSeenUpdate(newDatabaseLsn) {
|
|
657
|
+
for (const [dbLsn, snapshots] of this.snapshotsByDatabaseLsn.entries()) {
|
|
658
|
+
if (dbLsn <= newDatabaseLsn) {
|
|
659
|
+
for (const snapshot of snapshots) {
|
|
660
|
+
this.removeSnapshot(snapshot);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
|
|
568
667
|
// src/client.ts
|
|
569
668
|
var RESERVED_PARAMS = /* @__PURE__ */ new Set([
|
|
570
669
|
LIVE_CACHE_BUSTER_QUERY_PARAM,
|
|
@@ -612,9 +711,8 @@ function canonicalShapeKey(url) {
|
|
|
612
711
|
cleanUrl.searchParams.sort();
|
|
613
712
|
return cleanUrl.toString();
|
|
614
713
|
}
|
|
615
|
-
var _error, _fetchClient2, _sseFetchClient, _messageParser, _subscribers, _started, _state, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _connected, _shapeHandle, _schema, _onError, _requestAbortController, _isRefreshing, _tickPromise, _tickPromiseResolver, _tickPromiseRejecter, _messageChain, _ShapeStream_instances, start_fn, requestShape_fn, constructUrl_fn, createAbortListener_fn, onInitialResponse_fn, onMessages_fn, fetchShape_fn, requestShapeLongPoll_fn, requestShapeSSE_fn, pause_fn, resume_fn, nextTick_fn, publish_fn, sendErrorToSubscribers_fn, subscribeToVisibilityChanges_fn, reset_fn;
|
|
714
|
+
var _error, _fetchClient2, _sseFetchClient, _messageParser, _subscribers, _started, _state, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _isMidStream, _connected, _shapeHandle, _mode, _schema, _onError, _requestAbortController, _isRefreshing, _tickPromise, _tickPromiseResolver, _tickPromiseRejecter, _messageChain, _snapshotTracker, _activeSnapshotRequests, _midStreamPromise, _midStreamPromiseResolver, _ShapeStream_instances, start_fn, requestShape_fn, constructUrl_fn, createAbortListener_fn, onInitialResponse_fn, onMessages_fn, fetchShape_fn, requestShapeLongPoll_fn, requestShapeSSE_fn, pause_fn, resume_fn, nextTick_fn, waitForStreamEnd_fn, publish_fn, sendErrorToSubscribers_fn, subscribeToVisibilityChanges_fn, reset_fn, fetchSnapshot_fn;
|
|
616
715
|
var ShapeStream = class {
|
|
617
|
-
// promise chain for incoming messages
|
|
618
716
|
constructor(options) {
|
|
619
717
|
__privateAdd(this, _ShapeStream_instances);
|
|
620
718
|
__privateAdd(this, _error, null);
|
|
@@ -630,8 +728,10 @@ var ShapeStream = class {
|
|
|
630
728
|
__privateAdd(this, _lastSyncedAt);
|
|
631
729
|
// unix time
|
|
632
730
|
__privateAdd(this, _isUpToDate, false);
|
|
731
|
+
__privateAdd(this, _isMidStream, true);
|
|
633
732
|
__privateAdd(this, _connected, false);
|
|
634
733
|
__privateAdd(this, _shapeHandle);
|
|
734
|
+
__privateAdd(this, _mode);
|
|
635
735
|
__privateAdd(this, _schema);
|
|
636
736
|
__privateAdd(this, _onError);
|
|
637
737
|
__privateAdd(this, _requestAbortController);
|
|
@@ -640,7 +740,13 @@ var ShapeStream = class {
|
|
|
640
740
|
__privateAdd(this, _tickPromiseResolver);
|
|
641
741
|
__privateAdd(this, _tickPromiseRejecter);
|
|
642
742
|
__privateAdd(this, _messageChain, Promise.resolve([]));
|
|
643
|
-
|
|
743
|
+
// promise chain for incoming messages
|
|
744
|
+
__privateAdd(this, _snapshotTracker, new SnapshotTracker());
|
|
745
|
+
__privateAdd(this, _activeSnapshotRequests, 0);
|
|
746
|
+
// counter for concurrent snapshot requests
|
|
747
|
+
__privateAdd(this, _midStreamPromise);
|
|
748
|
+
__privateAdd(this, _midStreamPromiseResolver);
|
|
749
|
+
var _a, _b, _c, _d;
|
|
644
750
|
this.options = __spreadValues({ subscribe: true }, options);
|
|
645
751
|
validateOptions(this.options);
|
|
646
752
|
__privateSet(this, _lastOffset, (_a = this.options.offset) != null ? _a : `-1`);
|
|
@@ -651,8 +757,9 @@ var ShapeStream = class {
|
|
|
651
757
|
options.transformer
|
|
652
758
|
));
|
|
653
759
|
__privateSet(this, _onError, this.options.onError);
|
|
654
|
-
|
|
655
|
-
const
|
|
760
|
+
__privateSet(this, _mode, (_b = this.options.mode) != null ? _b : `full`);
|
|
761
|
+
const baseFetchClient = (_c = options.fetchClient) != null ? _c : (...args) => fetch(...args);
|
|
762
|
+
const backOffOpts = __spreadProps(__spreadValues({}, (_d = options.backoffOptions) != null ? _d : BackoffDefaults), {
|
|
656
763
|
onFailedAttempt: () => {
|
|
657
764
|
var _a2, _b2;
|
|
658
765
|
__privateSet(this, _connected, false);
|
|
@@ -681,6 +788,9 @@ var ShapeStream = class {
|
|
|
681
788
|
get lastOffset() {
|
|
682
789
|
return __privateGet(this, _lastOffset);
|
|
683
790
|
}
|
|
791
|
+
get mode() {
|
|
792
|
+
return __privateGet(this, _mode);
|
|
793
|
+
}
|
|
684
794
|
subscribe(callback, onError = () => {
|
|
685
795
|
}) {
|
|
686
796
|
const subscriptionId = Math.random();
|
|
@@ -731,6 +841,54 @@ var ShapeStream = class {
|
|
|
731
841
|
await __privateMethod(this, _ShapeStream_instances, nextTick_fn).call(this);
|
|
732
842
|
__privateSet(this, _isRefreshing, false);
|
|
733
843
|
}
|
|
844
|
+
/**
|
|
845
|
+
* Request a snapshot for subset of data.
|
|
846
|
+
*
|
|
847
|
+
* Only available when mode is `changes_only`.
|
|
848
|
+
* Returns the insertion point & the data, but more importantly injects the data
|
|
849
|
+
* into the subscribed data stream. Returned value is unlikely to be useful for the caller,
|
|
850
|
+
* unless the caller has complicated additional logic.
|
|
851
|
+
*
|
|
852
|
+
* Data will be injected in a way that's also tracking further incoming changes, and it'll
|
|
853
|
+
* skip the ones that are already in the snapshot.
|
|
854
|
+
*
|
|
855
|
+
* @param opts - The options for the snapshot request.
|
|
856
|
+
* @returns The metadata and the data for the snapshot.
|
|
857
|
+
*/
|
|
858
|
+
async requestSnapshot(opts) {
|
|
859
|
+
if (__privateGet(this, _mode) === `full`) {
|
|
860
|
+
throw new Error(
|
|
861
|
+
`Snapshot requests are not supported in ${__privateGet(this, _mode)} mode, as the consumer is guaranteed to observe all data`
|
|
862
|
+
);
|
|
863
|
+
}
|
|
864
|
+
if (!__privateGet(this, _started)) await __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
|
|
865
|
+
await __privateMethod(this, _ShapeStream_instances, waitForStreamEnd_fn).call(this);
|
|
866
|
+
__privateWrapper(this, _activeSnapshotRequests)._++;
|
|
867
|
+
try {
|
|
868
|
+
if (__privateGet(this, _activeSnapshotRequests) === 1) {
|
|
869
|
+
__privateMethod(this, _ShapeStream_instances, pause_fn).call(this);
|
|
870
|
+
}
|
|
871
|
+
const { fetchUrl, requestHeaders } = await __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, this.options.url, true, opts);
|
|
872
|
+
const { metadata, data } = await __privateMethod(this, _ShapeStream_instances, fetchSnapshot_fn).call(this, fetchUrl, requestHeaders);
|
|
873
|
+
const dataWithEndBoundary = data.concat([
|
|
874
|
+
{ headers: __spreadValues({ control: `snapshot-end` }, metadata) }
|
|
875
|
+
]);
|
|
876
|
+
__privateGet(this, _snapshotTracker).addSnapshot(
|
|
877
|
+
metadata,
|
|
878
|
+
new Set(data.map((message) => message.key))
|
|
879
|
+
);
|
|
880
|
+
__privateMethod(this, _ShapeStream_instances, onMessages_fn).call(this, dataWithEndBoundary, false);
|
|
881
|
+
return {
|
|
882
|
+
metadata,
|
|
883
|
+
data
|
|
884
|
+
};
|
|
885
|
+
} finally {
|
|
886
|
+
__privateWrapper(this, _activeSnapshotRequests)._--;
|
|
887
|
+
if (__privateGet(this, _activeSnapshotRequests) === 0) {
|
|
888
|
+
__privateMethod(this, _ShapeStream_instances, resume_fn).call(this);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
734
892
|
};
|
|
735
893
|
_error = new WeakMap();
|
|
736
894
|
_fetchClient2 = new WeakMap();
|
|
@@ -743,8 +901,10 @@ _lastOffset = new WeakMap();
|
|
|
743
901
|
_liveCacheBuster = new WeakMap();
|
|
744
902
|
_lastSyncedAt = new WeakMap();
|
|
745
903
|
_isUpToDate = new WeakMap();
|
|
904
|
+
_isMidStream = new WeakMap();
|
|
746
905
|
_connected = new WeakMap();
|
|
747
906
|
_shapeHandle = new WeakMap();
|
|
907
|
+
_mode = new WeakMap();
|
|
748
908
|
_schema = new WeakMap();
|
|
749
909
|
_onError = new WeakMap();
|
|
750
910
|
_requestAbortController = new WeakMap();
|
|
@@ -753,6 +913,10 @@ _tickPromise = new WeakMap();
|
|
|
753
913
|
_tickPromiseResolver = new WeakMap();
|
|
754
914
|
_tickPromiseRejecter = new WeakMap();
|
|
755
915
|
_messageChain = new WeakMap();
|
|
916
|
+
_snapshotTracker = new WeakMap();
|
|
917
|
+
_activeSnapshotRequests = new WeakMap();
|
|
918
|
+
_midStreamPromise = new WeakMap();
|
|
919
|
+
_midStreamPromiseResolver = new WeakMap();
|
|
756
920
|
_ShapeStream_instances = new WeakSet();
|
|
757
921
|
start_fn = async function() {
|
|
758
922
|
var _a;
|
|
@@ -837,14 +1001,12 @@ requestShape_fn = async function() {
|
|
|
837
1001
|
(_b = __privateGet(this, _tickPromiseResolver)) == null ? void 0 : _b.call(this);
|
|
838
1002
|
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
839
1003
|
};
|
|
840
|
-
constructUrl_fn = async function(url, resumingFromPause) {
|
|
1004
|
+
constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
|
|
841
1005
|
const [requestHeaders, params] = await Promise.all([
|
|
842
1006
|
resolveHeaders(this.options.headers),
|
|
843
1007
|
this.options.params ? toInternalParams(convertWhereParamsToObj(this.options.params)) : void 0
|
|
844
1008
|
]);
|
|
845
|
-
if (params)
|
|
846
|
-
validateParams(params);
|
|
847
|
-
}
|
|
1009
|
+
if (params) validateParams(params);
|
|
848
1010
|
const fetchUrl = new URL(url);
|
|
849
1011
|
if (params) {
|
|
850
1012
|
if (params.table) setQueryParam(fetchUrl, TABLE_QUERY_PARAM, params.table);
|
|
@@ -864,7 +1026,20 @@ constructUrl_fn = async function(url, resumingFromPause) {
|
|
|
864
1026
|
setQueryParam(fetchUrl, key, value);
|
|
865
1027
|
}
|
|
866
1028
|
}
|
|
1029
|
+
if (subsetParams) {
|
|
1030
|
+
if (subsetParams.where)
|
|
1031
|
+
setQueryParam(fetchUrl, SUBSET_PARAM_WHERE, subsetParams.where);
|
|
1032
|
+
if (subsetParams.params)
|
|
1033
|
+
setQueryParam(fetchUrl, SUBSET_PARAM_WHERE_PARAMS, subsetParams.params);
|
|
1034
|
+
if (subsetParams.limit)
|
|
1035
|
+
setQueryParam(fetchUrl, SUBSET_PARAM_LIMIT, subsetParams.limit);
|
|
1036
|
+
if (subsetParams.offset)
|
|
1037
|
+
setQueryParam(fetchUrl, SUBSET_PARAM_OFFSET, subsetParams.offset);
|
|
1038
|
+
if (subsetParams.orderBy)
|
|
1039
|
+
setQueryParam(fetchUrl, SUBSET_PARAM_ORDER_BY, subsetParams.orderBy);
|
|
1040
|
+
}
|
|
867
1041
|
fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
|
|
1042
|
+
fetchUrl.searchParams.set(LOG_MODE_QUERY_PARAM, __privateGet(this, _mode));
|
|
868
1043
|
if (__privateGet(this, _isUpToDate)) {
|
|
869
1044
|
if (!__privateGet(this, _isRefreshing) && !resumingFromPause) {
|
|
870
1045
|
fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
|
|
@@ -928,7 +1103,9 @@ onInitialResponse_fn = async function(response) {
|
|
|
928
1103
|
}
|
|
929
1104
|
};
|
|
930
1105
|
onMessages_fn = async function(batch, isSseMessage = false) {
|
|
1106
|
+
var _a;
|
|
931
1107
|
if (batch.length > 0) {
|
|
1108
|
+
__privateSet(this, _isMidStream, true);
|
|
932
1109
|
const lastMessage = batch[batch.length - 1];
|
|
933
1110
|
if (isUpToDateMessage(lastMessage)) {
|
|
934
1111
|
if (isSseMessage) {
|
|
@@ -939,8 +1116,16 @@ onMessages_fn = async function(batch, isSseMessage = false) {
|
|
|
939
1116
|
}
|
|
940
1117
|
__privateSet(this, _lastSyncedAt, Date.now());
|
|
941
1118
|
__privateSet(this, _isUpToDate, true);
|
|
1119
|
+
__privateSet(this, _isMidStream, false);
|
|
1120
|
+
(_a = __privateGet(this, _midStreamPromiseResolver)) == null ? void 0 : _a.call(this);
|
|
942
1121
|
}
|
|
943
|
-
|
|
1122
|
+
const messagesToProcess = batch.filter((message) => {
|
|
1123
|
+
if (isChangeMessage(message)) {
|
|
1124
|
+
return !__privateGet(this, _snapshotTracker).shouldRejectMessage(message);
|
|
1125
|
+
}
|
|
1126
|
+
return true;
|
|
1127
|
+
});
|
|
1128
|
+
await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, messagesToProcess);
|
|
944
1129
|
}
|
|
945
1130
|
};
|
|
946
1131
|
fetchShape_fn = async function(opts) {
|
|
@@ -1029,6 +1214,22 @@ nextTick_fn = async function() {
|
|
|
1029
1214
|
});
|
|
1030
1215
|
return __privateGet(this, _tickPromise);
|
|
1031
1216
|
};
|
|
1217
|
+
waitForStreamEnd_fn = async function() {
|
|
1218
|
+
if (!__privateGet(this, _isMidStream)) {
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
if (__privateGet(this, _midStreamPromise)) {
|
|
1222
|
+
return __privateGet(this, _midStreamPromise);
|
|
1223
|
+
}
|
|
1224
|
+
__privateSet(this, _midStreamPromise, new Promise((resolve) => {
|
|
1225
|
+
__privateSet(this, _midStreamPromiseResolver, resolve);
|
|
1226
|
+
}));
|
|
1227
|
+
__privateGet(this, _midStreamPromise).finally(() => {
|
|
1228
|
+
__privateSet(this, _midStreamPromise, void 0);
|
|
1229
|
+
__privateSet(this, _midStreamPromiseResolver, void 0);
|
|
1230
|
+
});
|
|
1231
|
+
return __privateGet(this, _midStreamPromise);
|
|
1232
|
+
};
|
|
1032
1233
|
publish_fn = async function(messages) {
|
|
1033
1234
|
__privateSet(this, _messageChain, __privateGet(this, _messageChain).then(
|
|
1034
1235
|
() => Promise.all(
|
|
@@ -1071,8 +1272,31 @@ reset_fn = function(handle) {
|
|
|
1071
1272
|
__privateSet(this, _liveCacheBuster, ``);
|
|
1072
1273
|
__privateSet(this, _shapeHandle, handle);
|
|
1073
1274
|
__privateSet(this, _isUpToDate, false);
|
|
1275
|
+
__privateSet(this, _isMidStream, true);
|
|
1074
1276
|
__privateSet(this, _connected, false);
|
|
1075
1277
|
__privateSet(this, _schema, void 0);
|
|
1278
|
+
__privateSet(this, _activeSnapshotRequests, 0);
|
|
1279
|
+
};
|
|
1280
|
+
fetchSnapshot_fn = async function(url, headers) {
|
|
1281
|
+
const response = await __privateGet(this, _fetchClient2).call(this, url.toString(), { headers });
|
|
1282
|
+
if (!response.ok) {
|
|
1283
|
+
throw new FetchError(
|
|
1284
|
+
response.status,
|
|
1285
|
+
void 0,
|
|
1286
|
+
void 0,
|
|
1287
|
+
Object.fromEntries([...response.headers.entries()]),
|
|
1288
|
+
url.toString()
|
|
1289
|
+
);
|
|
1290
|
+
}
|
|
1291
|
+
const { metadata, data } = await response.json();
|
|
1292
|
+
const batch = __privateGet(this, _messageParser).parse(
|
|
1293
|
+
JSON.stringify(data),
|
|
1294
|
+
__privateGet(this, _schema)
|
|
1295
|
+
);
|
|
1296
|
+
return {
|
|
1297
|
+
metadata,
|
|
1298
|
+
data: batch
|
|
1299
|
+
};
|
|
1076
1300
|
};
|
|
1077
1301
|
ShapeStream.Replica = {
|
|
1078
1302
|
FULL: `full`,
|
|
@@ -1094,7 +1318,7 @@ function validateOptions(options) {
|
|
|
1094
1318
|
if (options.signal && !(options.signal instanceof AbortSignal)) {
|
|
1095
1319
|
throw new InvalidSignalError();
|
|
1096
1320
|
}
|
|
1097
|
-
if (options.offset !== void 0 && options.offset !== `-1` && !options.handle) {
|
|
1321
|
+
if (options.offset !== void 0 && options.offset !== `-1` && options.offset !== `now` && !options.handle) {
|
|
1098
1322
|
throw new MissingShapeHandleError();
|
|
1099
1323
|
}
|
|
1100
1324
|
validateParams(options.params);
|
|
@@ -1123,12 +1347,15 @@ function convertWhereParamsToObj(allPgParams) {
|
|
|
1123
1347
|
}
|
|
1124
1348
|
|
|
1125
1349
|
// src/shape.ts
|
|
1126
|
-
var _data, _subscribers2, _status, _error2, _Shape_instances, process_fn, updateShapeStatus_fn, handleError_fn, notify_fn;
|
|
1350
|
+
var _data, _subscribers2, _insertedKeys, _requestedSubSnapshots, _reexecuteSnapshotsPending, _status, _error2, _Shape_instances, process_fn, reexecuteSnapshots_fn, awaitUpToDate_fn, updateShapeStatus_fn, handleError_fn, notify_fn;
|
|
1127
1351
|
var Shape = class {
|
|
1128
1352
|
constructor(stream) {
|
|
1129
1353
|
__privateAdd(this, _Shape_instances);
|
|
1130
1354
|
__privateAdd(this, _data, /* @__PURE__ */ new Map());
|
|
1131
1355
|
__privateAdd(this, _subscribers2, /* @__PURE__ */ new Map());
|
|
1356
|
+
__privateAdd(this, _insertedKeys, /* @__PURE__ */ new Set());
|
|
1357
|
+
__privateAdd(this, _requestedSubSnapshots, /* @__PURE__ */ new Set());
|
|
1358
|
+
__privateAdd(this, _reexecuteSnapshotsPending, false);
|
|
1132
1359
|
__privateAdd(this, _status, `syncing`);
|
|
1133
1360
|
__privateAdd(this, _error2, false);
|
|
1134
1361
|
this.stream = stream;
|
|
@@ -1187,6 +1414,20 @@ var Shape = class {
|
|
|
1187
1414
|
isConnected() {
|
|
1188
1415
|
return this.stream.isConnected();
|
|
1189
1416
|
}
|
|
1417
|
+
/** Current log mode of the underlying stream */
|
|
1418
|
+
get mode() {
|
|
1419
|
+
return this.stream.mode;
|
|
1420
|
+
}
|
|
1421
|
+
/**
|
|
1422
|
+
* Request a snapshot for subset of data. Only available when mode is changes_only.
|
|
1423
|
+
* Returns void; data will be emitted via the stream and processed by this Shape.
|
|
1424
|
+
*/
|
|
1425
|
+
async requestSnapshot(params) {
|
|
1426
|
+
const key = JSON.stringify(params);
|
|
1427
|
+
__privateGet(this, _requestedSubSnapshots).add(key);
|
|
1428
|
+
await __privateMethod(this, _Shape_instances, awaitUpToDate_fn).call(this);
|
|
1429
|
+
await this.stream.requestSnapshot(params);
|
|
1430
|
+
}
|
|
1190
1431
|
subscribe(callback) {
|
|
1191
1432
|
const subscriptionId = Math.random();
|
|
1192
1433
|
__privateGet(this, _subscribers2).set(subscriptionId, callback);
|
|
@@ -1203,6 +1444,9 @@ var Shape = class {
|
|
|
1203
1444
|
};
|
|
1204
1445
|
_data = new WeakMap();
|
|
1205
1446
|
_subscribers2 = new WeakMap();
|
|
1447
|
+
_insertedKeys = new WeakMap();
|
|
1448
|
+
_requestedSubSnapshots = new WeakMap();
|
|
1449
|
+
_reexecuteSnapshotsPending = new WeakMap();
|
|
1206
1450
|
_status = new WeakMap();
|
|
1207
1451
|
_error2 = new WeakMap();
|
|
1208
1452
|
_Shape_instances = new WeakSet();
|
|
@@ -1211,33 +1455,89 @@ process_fn = function(messages) {
|
|
|
1211
1455
|
messages.forEach((message) => {
|
|
1212
1456
|
if (isChangeMessage(message)) {
|
|
1213
1457
|
shouldNotify = __privateMethod(this, _Shape_instances, updateShapeStatus_fn).call(this, `syncing`);
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1458
|
+
if (this.mode === `full`) {
|
|
1459
|
+
switch (message.headers.operation) {
|
|
1460
|
+
case `insert`:
|
|
1461
|
+
__privateGet(this, _data).set(message.key, message.value);
|
|
1462
|
+
break;
|
|
1463
|
+
case `update`:
|
|
1464
|
+
__privateGet(this, _data).set(message.key, __spreadValues(__spreadValues({}, __privateGet(this, _data).get(message.key)), message.value));
|
|
1465
|
+
break;
|
|
1466
|
+
case `delete`:
|
|
1467
|
+
__privateGet(this, _data).delete(message.key);
|
|
1468
|
+
break;
|
|
1469
|
+
}
|
|
1470
|
+
} else {
|
|
1471
|
+
switch (message.headers.operation) {
|
|
1472
|
+
case `insert`:
|
|
1473
|
+
__privateGet(this, _insertedKeys).add(message.key);
|
|
1474
|
+
__privateGet(this, _data).set(message.key, message.value);
|
|
1475
|
+
break;
|
|
1476
|
+
case `update`:
|
|
1477
|
+
if (__privateGet(this, _insertedKeys).has(message.key)) {
|
|
1478
|
+
__privateGet(this, _data).set(message.key, __spreadValues(__spreadValues({}, __privateGet(this, _data).get(message.key)), message.value));
|
|
1479
|
+
}
|
|
1480
|
+
break;
|
|
1481
|
+
case `delete`:
|
|
1482
|
+
if (__privateGet(this, _insertedKeys).has(message.key)) {
|
|
1483
|
+
__privateGet(this, _data).delete(message.key);
|
|
1484
|
+
__privateGet(this, _insertedKeys).delete(message.key);
|
|
1485
|
+
}
|
|
1486
|
+
break;
|
|
1487
|
+
}
|
|
1224
1488
|
}
|
|
1225
1489
|
}
|
|
1226
1490
|
if (isControlMessage(message)) {
|
|
1227
1491
|
switch (message.headers.control) {
|
|
1228
1492
|
case `up-to-date`:
|
|
1229
1493
|
shouldNotify = __privateMethod(this, _Shape_instances, updateShapeStatus_fn).call(this, `up-to-date`);
|
|
1494
|
+
if (__privateGet(this, _reexecuteSnapshotsPending)) {
|
|
1495
|
+
__privateSet(this, _reexecuteSnapshotsPending, false);
|
|
1496
|
+
void __privateMethod(this, _Shape_instances, reexecuteSnapshots_fn).call(this);
|
|
1497
|
+
}
|
|
1230
1498
|
break;
|
|
1231
1499
|
case `must-refetch`:
|
|
1232
1500
|
__privateGet(this, _data).clear();
|
|
1501
|
+
__privateGet(this, _insertedKeys).clear();
|
|
1233
1502
|
__privateSet(this, _error2, false);
|
|
1234
1503
|
shouldNotify = __privateMethod(this, _Shape_instances, updateShapeStatus_fn).call(this, `syncing`);
|
|
1504
|
+
__privateSet(this, _reexecuteSnapshotsPending, true);
|
|
1235
1505
|
break;
|
|
1236
1506
|
}
|
|
1237
1507
|
}
|
|
1238
1508
|
});
|
|
1239
1509
|
if (shouldNotify) __privateMethod(this, _Shape_instances, notify_fn).call(this);
|
|
1240
1510
|
};
|
|
1511
|
+
reexecuteSnapshots_fn = async function() {
|
|
1512
|
+
await __privateMethod(this, _Shape_instances, awaitUpToDate_fn).call(this);
|
|
1513
|
+
await Promise.all(
|
|
1514
|
+
Array.from(__privateGet(this, _requestedSubSnapshots)).map(async (jsonParams) => {
|
|
1515
|
+
try {
|
|
1516
|
+
const snapshot = JSON.parse(jsonParams);
|
|
1517
|
+
await this.stream.requestSnapshot(snapshot);
|
|
1518
|
+
} catch (_) {
|
|
1519
|
+
}
|
|
1520
|
+
})
|
|
1521
|
+
);
|
|
1522
|
+
};
|
|
1523
|
+
awaitUpToDate_fn = async function() {
|
|
1524
|
+
if (this.stream.isUpToDate) return;
|
|
1525
|
+
await new Promise((resolve) => {
|
|
1526
|
+
const check = () => {
|
|
1527
|
+
if (this.stream.isUpToDate) {
|
|
1528
|
+
clearInterval(interval);
|
|
1529
|
+
unsub();
|
|
1530
|
+
resolve();
|
|
1531
|
+
}
|
|
1532
|
+
};
|
|
1533
|
+
const interval = setInterval(check, 10);
|
|
1534
|
+
const unsub = this.stream.subscribe(
|
|
1535
|
+
() => check(),
|
|
1536
|
+
() => check()
|
|
1537
|
+
);
|
|
1538
|
+
check();
|
|
1539
|
+
});
|
|
1540
|
+
};
|
|
1241
1541
|
updateShapeStatus_fn = function(status) {
|
|
1242
1542
|
const stateChanged = __privateGet(this, _status) !== status;
|
|
1243
1543
|
__privateSet(this, _status, status);
|
|
@@ -1262,6 +1562,7 @@ export {
|
|
|
1262
1562
|
ShapeStream,
|
|
1263
1563
|
isChangeMessage,
|
|
1264
1564
|
isControlMessage,
|
|
1565
|
+
isVisibleInSnapshot,
|
|
1265
1566
|
resolveValue
|
|
1266
1567
|
};
|
|
1267
1568
|
//# sourceMappingURL=index.legacy-esm.js.map
|