@electric-sql/client 1.0.10 → 1.0.12
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.mjs
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
|
var __async = (__this, __arguments, generator) => {
|
|
41
49
|
return new Promise((resolve, reject) => {
|
|
42
50
|
var fulfilled = (value) => {
|
|
@@ -278,6 +286,13 @@ function getOffset(message) {
|
|
|
278
286
|
}
|
|
279
287
|
return `${lsn}_0`;
|
|
280
288
|
}
|
|
289
|
+
function isVisibleInSnapshot(txid, snapshot) {
|
|
290
|
+
const xid = BigInt(txid);
|
|
291
|
+
const xmin = BigInt(snapshot.xmin);
|
|
292
|
+
const xmax = BigInt(snapshot.xmax);
|
|
293
|
+
const xip = snapshot.xip_list.map(BigInt);
|
|
294
|
+
return xid < xmin || xid < xmax && !xip.includes(xid);
|
|
295
|
+
}
|
|
281
296
|
|
|
282
297
|
// src/constants.ts
|
|
283
298
|
var LIVE_CACHE_BUSTER_HEADER = `electric-cursor`;
|
|
@@ -298,12 +313,24 @@ var WHERE_PARAMS_PARAM = `params`;
|
|
|
298
313
|
var EXPERIMENTAL_LIVE_SSE_QUERY_PARAM = `experimental_live_sse`;
|
|
299
314
|
var FORCE_DISCONNECT_AND_REFRESH = `force-disconnect-and-refresh`;
|
|
300
315
|
var PAUSE_STREAM = `pause-stream`;
|
|
316
|
+
var LOG_MODE_QUERY_PARAM = `log`;
|
|
317
|
+
var SUBSET_PARAM_WHERE = `subset__where`;
|
|
318
|
+
var SUBSET_PARAM_LIMIT = `subset__limit`;
|
|
319
|
+
var SUBSET_PARAM_OFFSET = `subset__offset`;
|
|
320
|
+
var SUBSET_PARAM_ORDER_BY = `subset__order_by`;
|
|
321
|
+
var SUBSET_PARAM_WHERE_PARAMS = `subset__params`;
|
|
301
322
|
var ELECTRIC_PROTOCOL_QUERY_PARAMS = [
|
|
302
323
|
LIVE_QUERY_PARAM,
|
|
303
324
|
SHAPE_HANDLE_QUERY_PARAM,
|
|
304
325
|
OFFSET_QUERY_PARAM,
|
|
305
326
|
LIVE_CACHE_BUSTER_QUERY_PARAM,
|
|
306
|
-
EXPIRED_HANDLE_QUERY_PARAM
|
|
327
|
+
EXPIRED_HANDLE_QUERY_PARAM,
|
|
328
|
+
LOG_MODE_QUERY_PARAM,
|
|
329
|
+
SUBSET_PARAM_WHERE,
|
|
330
|
+
SUBSET_PARAM_LIMIT,
|
|
331
|
+
SUBSET_PARAM_OFFSET,
|
|
332
|
+
SUBSET_PARAM_ORDER_BY,
|
|
333
|
+
SUBSET_PARAM_WHERE_PARAMS
|
|
307
334
|
];
|
|
308
335
|
|
|
309
336
|
// src/fetch.ts
|
|
@@ -414,10 +441,20 @@ function createFetchWithResponseHeadersCheck(fetchClient) {
|
|
|
414
441
|
const headers = response.headers;
|
|
415
442
|
const missingHeaders = [];
|
|
416
443
|
const addMissingHeaders = (requiredHeaders) => missingHeaders.push(...requiredHeaders.filter((h) => !headers.has(h)));
|
|
417
|
-
addMissingHeaders(requiredElectricResponseHeaders);
|
|
418
444
|
const input = args[0];
|
|
419
445
|
const urlString = input.toString();
|
|
420
446
|
const url = new URL(urlString);
|
|
447
|
+
const isSnapshotRequest = [
|
|
448
|
+
SUBSET_PARAM_WHERE,
|
|
449
|
+
SUBSET_PARAM_WHERE_PARAMS,
|
|
450
|
+
SUBSET_PARAM_LIMIT,
|
|
451
|
+
SUBSET_PARAM_OFFSET,
|
|
452
|
+
SUBSET_PARAM_ORDER_BY
|
|
453
|
+
].some((p) => url.searchParams.has(p));
|
|
454
|
+
if (isSnapshotRequest) {
|
|
455
|
+
return response;
|
|
456
|
+
}
|
|
457
|
+
addMissingHeaders(requiredElectricResponseHeaders);
|
|
421
458
|
if (url.searchParams.get(LIVE_QUERY_PARAM) === `true`) {
|
|
422
459
|
addMissingHeaders(requiredLiveResponseHeaders);
|
|
423
460
|
}
|
|
@@ -587,6 +624,68 @@ var ExpiredShapesCache = class {
|
|
|
587
624
|
};
|
|
588
625
|
var expiredShapesCache = new ExpiredShapesCache();
|
|
589
626
|
|
|
627
|
+
// src/snapshot-tracker.ts
|
|
628
|
+
var SnapshotTracker = class {
|
|
629
|
+
constructor() {
|
|
630
|
+
this.activeSnapshots = /* @__PURE__ */ new Map();
|
|
631
|
+
this.xmaxSnapshots = /* @__PURE__ */ new Map();
|
|
632
|
+
this.snapshotsByDatabaseLsn = /* @__PURE__ */ new Map();
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* Add a new snapshot for tracking
|
|
636
|
+
*/
|
|
637
|
+
addSnapshot(metadata, keys) {
|
|
638
|
+
var _a, _b, _c, _d;
|
|
639
|
+
this.activeSnapshots.set(metadata.snapshot_mark, {
|
|
640
|
+
xmin: BigInt(metadata.xmin),
|
|
641
|
+
xmax: BigInt(metadata.xmax),
|
|
642
|
+
xip_list: metadata.xip_list.map(BigInt),
|
|
643
|
+
keys
|
|
644
|
+
});
|
|
645
|
+
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]);
|
|
646
|
+
this.xmaxSnapshots.set(BigInt(metadata.xmax), xmaxSet);
|
|
647
|
+
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]);
|
|
648
|
+
this.snapshotsByDatabaseLsn.set(
|
|
649
|
+
BigInt(metadata.database_lsn),
|
|
650
|
+
databaseLsnSet
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Remove a snapshot from tracking
|
|
655
|
+
*/
|
|
656
|
+
removeSnapshot(snapshotMark) {
|
|
657
|
+
this.activeSnapshots.delete(snapshotMark);
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Check if a change message should be filtered because its already in an active snapshot
|
|
661
|
+
* Returns true if the message should be filtered out (not processed)
|
|
662
|
+
*/
|
|
663
|
+
shouldRejectMessage(message) {
|
|
664
|
+
const txids = message.headers.txids || [];
|
|
665
|
+
if (txids.length === 0) return false;
|
|
666
|
+
const xid = Math.max(...txids);
|
|
667
|
+
for (const [xmax, snapshots] of this.xmaxSnapshots.entries()) {
|
|
668
|
+
if (xid >= xmax) {
|
|
669
|
+
for (const snapshot of snapshots) {
|
|
670
|
+
this.removeSnapshot(snapshot);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
return [...this.activeSnapshots.values()].some(
|
|
675
|
+
(x) => x.keys.has(message.key) && isVisibleInSnapshot(xid, x)
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
lastSeenUpdate(newDatabaseLsn) {
|
|
679
|
+
for (const [dbLsn, snapshots] of this.snapshotsByDatabaseLsn.entries()) {
|
|
680
|
+
if (dbLsn <= newDatabaseLsn) {
|
|
681
|
+
for (const snapshot of snapshots) {
|
|
682
|
+
this.removeSnapshot(snapshot);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
|
|
590
689
|
// src/client.ts
|
|
591
690
|
var RESERVED_PARAMS = /* @__PURE__ */ new Set([
|
|
592
691
|
LIVE_CACHE_BUSTER_QUERY_PARAM,
|
|
@@ -642,9 +741,8 @@ function canonicalShapeKey(url) {
|
|
|
642
741
|
cleanUrl.searchParams.sort();
|
|
643
742
|
return cleanUrl.toString();
|
|
644
743
|
}
|
|
645
|
-
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;
|
|
744
|
+
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;
|
|
646
745
|
var ShapeStream = class {
|
|
647
|
-
// promise chain for incoming messages
|
|
648
746
|
constructor(options) {
|
|
649
747
|
__privateAdd(this, _ShapeStream_instances);
|
|
650
748
|
__privateAdd(this, _error, null);
|
|
@@ -660,8 +758,10 @@ var ShapeStream = class {
|
|
|
660
758
|
__privateAdd(this, _lastSyncedAt);
|
|
661
759
|
// unix time
|
|
662
760
|
__privateAdd(this, _isUpToDate, false);
|
|
761
|
+
__privateAdd(this, _isMidStream, true);
|
|
663
762
|
__privateAdd(this, _connected, false);
|
|
664
763
|
__privateAdd(this, _shapeHandle);
|
|
764
|
+
__privateAdd(this, _mode);
|
|
665
765
|
__privateAdd(this, _schema);
|
|
666
766
|
__privateAdd(this, _onError);
|
|
667
767
|
__privateAdd(this, _requestAbortController);
|
|
@@ -670,7 +770,13 @@ var ShapeStream = class {
|
|
|
670
770
|
__privateAdd(this, _tickPromiseResolver);
|
|
671
771
|
__privateAdd(this, _tickPromiseRejecter);
|
|
672
772
|
__privateAdd(this, _messageChain, Promise.resolve([]));
|
|
673
|
-
|
|
773
|
+
// promise chain for incoming messages
|
|
774
|
+
__privateAdd(this, _snapshotTracker, new SnapshotTracker());
|
|
775
|
+
__privateAdd(this, _activeSnapshotRequests, 0);
|
|
776
|
+
// counter for concurrent snapshot requests
|
|
777
|
+
__privateAdd(this, _midStreamPromise);
|
|
778
|
+
__privateAdd(this, _midStreamPromiseResolver);
|
|
779
|
+
var _a, _b, _c, _d;
|
|
674
780
|
this.options = __spreadValues({ subscribe: true }, options);
|
|
675
781
|
validateOptions(this.options);
|
|
676
782
|
__privateSet(this, _lastOffset, (_a = this.options.offset) != null ? _a : `-1`);
|
|
@@ -681,8 +787,9 @@ var ShapeStream = class {
|
|
|
681
787
|
options.transformer
|
|
682
788
|
));
|
|
683
789
|
__privateSet(this, _onError, this.options.onError);
|
|
684
|
-
|
|
685
|
-
const
|
|
790
|
+
__privateSet(this, _mode, (_b = this.options.log) != null ? _b : `full`);
|
|
791
|
+
const baseFetchClient = (_c = options.fetchClient) != null ? _c : (...args) => fetch(...args);
|
|
792
|
+
const backOffOpts = __spreadProps(__spreadValues({}, (_d = options.backoffOptions) != null ? _d : BackoffDefaults), {
|
|
686
793
|
onFailedAttempt: () => {
|
|
687
794
|
var _a2, _b2;
|
|
688
795
|
__privateSet(this, _connected, false);
|
|
@@ -711,6 +818,9 @@ var ShapeStream = class {
|
|
|
711
818
|
get lastOffset() {
|
|
712
819
|
return __privateGet(this, _lastOffset);
|
|
713
820
|
}
|
|
821
|
+
get mode() {
|
|
822
|
+
return __privateGet(this, _mode);
|
|
823
|
+
}
|
|
714
824
|
subscribe(callback, onError = () => {
|
|
715
825
|
}) {
|
|
716
826
|
const subscriptionId = Math.random();
|
|
@@ -763,6 +873,56 @@ var ShapeStream = class {
|
|
|
763
873
|
__privateSet(this, _isRefreshing, false);
|
|
764
874
|
});
|
|
765
875
|
}
|
|
876
|
+
/**
|
|
877
|
+
* Request a snapshot for subset of data.
|
|
878
|
+
*
|
|
879
|
+
* Only available when mode is `changes_only`.
|
|
880
|
+
* Returns the insertion point & the data, but more importantly injects the data
|
|
881
|
+
* into the subscribed data stream. Returned value is unlikely to be useful for the caller,
|
|
882
|
+
* unless the caller has complicated additional logic.
|
|
883
|
+
*
|
|
884
|
+
* Data will be injected in a way that's also tracking further incoming changes, and it'll
|
|
885
|
+
* skip the ones that are already in the snapshot.
|
|
886
|
+
*
|
|
887
|
+
* @param opts - The options for the snapshot request.
|
|
888
|
+
* @returns The metadata and the data for the snapshot.
|
|
889
|
+
*/
|
|
890
|
+
requestSnapshot(opts) {
|
|
891
|
+
return __async(this, null, function* () {
|
|
892
|
+
if (__privateGet(this, _mode) === `full`) {
|
|
893
|
+
throw new Error(
|
|
894
|
+
`Snapshot requests are not supported in ${__privateGet(this, _mode)} mode, as the consumer is guaranteed to observe all data`
|
|
895
|
+
);
|
|
896
|
+
}
|
|
897
|
+
if (!__privateGet(this, _started)) yield __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
|
|
898
|
+
yield __privateMethod(this, _ShapeStream_instances, waitForStreamEnd_fn).call(this);
|
|
899
|
+
__privateWrapper(this, _activeSnapshotRequests)._++;
|
|
900
|
+
try {
|
|
901
|
+
if (__privateGet(this, _activeSnapshotRequests) === 1) {
|
|
902
|
+
__privateMethod(this, _ShapeStream_instances, pause_fn).call(this);
|
|
903
|
+
}
|
|
904
|
+
const { fetchUrl, requestHeaders } = yield __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, this.options.url, true, opts);
|
|
905
|
+
const { metadata, data } = yield __privateMethod(this, _ShapeStream_instances, fetchSnapshot_fn).call(this, fetchUrl, requestHeaders);
|
|
906
|
+
const dataWithEndBoundary = data.concat([
|
|
907
|
+
{ headers: __spreadValues({ control: `snapshot-end` }, metadata) }
|
|
908
|
+
]);
|
|
909
|
+
__privateGet(this, _snapshotTracker).addSnapshot(
|
|
910
|
+
metadata,
|
|
911
|
+
new Set(data.map((message) => message.key))
|
|
912
|
+
);
|
|
913
|
+
__privateMethod(this, _ShapeStream_instances, onMessages_fn).call(this, dataWithEndBoundary, false);
|
|
914
|
+
return {
|
|
915
|
+
metadata,
|
|
916
|
+
data
|
|
917
|
+
};
|
|
918
|
+
} finally {
|
|
919
|
+
__privateWrapper(this, _activeSnapshotRequests)._--;
|
|
920
|
+
if (__privateGet(this, _activeSnapshotRequests) === 0) {
|
|
921
|
+
__privateMethod(this, _ShapeStream_instances, resume_fn).call(this);
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
});
|
|
925
|
+
}
|
|
766
926
|
};
|
|
767
927
|
_error = new WeakMap();
|
|
768
928
|
_fetchClient2 = new WeakMap();
|
|
@@ -775,8 +935,10 @@ _lastOffset = new WeakMap();
|
|
|
775
935
|
_liveCacheBuster = new WeakMap();
|
|
776
936
|
_lastSyncedAt = new WeakMap();
|
|
777
937
|
_isUpToDate = new WeakMap();
|
|
938
|
+
_isMidStream = new WeakMap();
|
|
778
939
|
_connected = new WeakMap();
|
|
779
940
|
_shapeHandle = new WeakMap();
|
|
941
|
+
_mode = new WeakMap();
|
|
780
942
|
_schema = new WeakMap();
|
|
781
943
|
_onError = new WeakMap();
|
|
782
944
|
_requestAbortController = new WeakMap();
|
|
@@ -785,6 +947,10 @@ _tickPromise = new WeakMap();
|
|
|
785
947
|
_tickPromiseResolver = new WeakMap();
|
|
786
948
|
_tickPromiseRejecter = new WeakMap();
|
|
787
949
|
_messageChain = new WeakMap();
|
|
950
|
+
_snapshotTracker = new WeakMap();
|
|
951
|
+
_activeSnapshotRequests = new WeakMap();
|
|
952
|
+
_midStreamPromise = new WeakMap();
|
|
953
|
+
_midStreamPromiseResolver = new WeakMap();
|
|
788
954
|
_ShapeStream_instances = new WeakSet();
|
|
789
955
|
start_fn = function() {
|
|
790
956
|
return __async(this, null, function* () {
|
|
@@ -873,15 +1039,13 @@ requestShape_fn = function() {
|
|
|
873
1039
|
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
874
1040
|
});
|
|
875
1041
|
};
|
|
876
|
-
constructUrl_fn = function(url, resumingFromPause) {
|
|
1042
|
+
constructUrl_fn = function(url, resumingFromPause, subsetParams) {
|
|
877
1043
|
return __async(this, null, function* () {
|
|
878
1044
|
const [requestHeaders, params] = yield Promise.all([
|
|
879
1045
|
resolveHeaders(this.options.headers),
|
|
880
1046
|
this.options.params ? toInternalParams(convertWhereParamsToObj(this.options.params)) : void 0
|
|
881
1047
|
]);
|
|
882
|
-
if (params)
|
|
883
|
-
validateParams(params);
|
|
884
|
-
}
|
|
1048
|
+
if (params) validateParams(params);
|
|
885
1049
|
const fetchUrl = new URL(url);
|
|
886
1050
|
if (params) {
|
|
887
1051
|
if (params.table) setQueryParam(fetchUrl, TABLE_QUERY_PARAM, params.table);
|
|
@@ -901,7 +1065,20 @@ constructUrl_fn = function(url, resumingFromPause) {
|
|
|
901
1065
|
setQueryParam(fetchUrl, key, value);
|
|
902
1066
|
}
|
|
903
1067
|
}
|
|
1068
|
+
if (subsetParams) {
|
|
1069
|
+
if (subsetParams.where)
|
|
1070
|
+
setQueryParam(fetchUrl, SUBSET_PARAM_WHERE, subsetParams.where);
|
|
1071
|
+
if (subsetParams.params)
|
|
1072
|
+
setQueryParam(fetchUrl, SUBSET_PARAM_WHERE_PARAMS, subsetParams.params);
|
|
1073
|
+
if (subsetParams.limit)
|
|
1074
|
+
setQueryParam(fetchUrl, SUBSET_PARAM_LIMIT, subsetParams.limit);
|
|
1075
|
+
if (subsetParams.offset)
|
|
1076
|
+
setQueryParam(fetchUrl, SUBSET_PARAM_OFFSET, subsetParams.offset);
|
|
1077
|
+
if (subsetParams.orderBy)
|
|
1078
|
+
setQueryParam(fetchUrl, SUBSET_PARAM_ORDER_BY, subsetParams.orderBy);
|
|
1079
|
+
}
|
|
904
1080
|
fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
|
|
1081
|
+
fetchUrl.searchParams.set(LOG_MODE_QUERY_PARAM, __privateGet(this, _mode));
|
|
905
1082
|
if (__privateGet(this, _isUpToDate)) {
|
|
906
1083
|
if (!__privateGet(this, _isRefreshing) && !resumingFromPause) {
|
|
907
1084
|
fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
|
|
@@ -971,7 +1148,9 @@ onInitialResponse_fn = function(response) {
|
|
|
971
1148
|
};
|
|
972
1149
|
onMessages_fn = function(batch, isSseMessage = false) {
|
|
973
1150
|
return __async(this, null, function* () {
|
|
1151
|
+
var _a;
|
|
974
1152
|
if (batch.length > 0) {
|
|
1153
|
+
__privateSet(this, _isMidStream, true);
|
|
975
1154
|
const lastMessage = batch[batch.length - 1];
|
|
976
1155
|
if (isUpToDateMessage(lastMessage)) {
|
|
977
1156
|
if (isSseMessage) {
|
|
@@ -982,8 +1161,16 @@ onMessages_fn = function(batch, isSseMessage = false) {
|
|
|
982
1161
|
}
|
|
983
1162
|
__privateSet(this, _lastSyncedAt, Date.now());
|
|
984
1163
|
__privateSet(this, _isUpToDate, true);
|
|
1164
|
+
__privateSet(this, _isMidStream, false);
|
|
1165
|
+
(_a = __privateGet(this, _midStreamPromiseResolver)) == null ? void 0 : _a.call(this);
|
|
985
1166
|
}
|
|
986
|
-
|
|
1167
|
+
const messagesToProcess = batch.filter((message) => {
|
|
1168
|
+
if (isChangeMessage(message)) {
|
|
1169
|
+
return !__privateGet(this, _snapshotTracker).shouldRejectMessage(message);
|
|
1170
|
+
}
|
|
1171
|
+
return true;
|
|
1172
|
+
});
|
|
1173
|
+
yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, messagesToProcess);
|
|
987
1174
|
}
|
|
988
1175
|
});
|
|
989
1176
|
};
|
|
@@ -1081,6 +1268,24 @@ nextTick_fn = function() {
|
|
|
1081
1268
|
return __privateGet(this, _tickPromise);
|
|
1082
1269
|
});
|
|
1083
1270
|
};
|
|
1271
|
+
waitForStreamEnd_fn = function() {
|
|
1272
|
+
return __async(this, null, function* () {
|
|
1273
|
+
if (!__privateGet(this, _isMidStream)) {
|
|
1274
|
+
return;
|
|
1275
|
+
}
|
|
1276
|
+
if (__privateGet(this, _midStreamPromise)) {
|
|
1277
|
+
return __privateGet(this, _midStreamPromise);
|
|
1278
|
+
}
|
|
1279
|
+
__privateSet(this, _midStreamPromise, new Promise((resolve) => {
|
|
1280
|
+
__privateSet(this, _midStreamPromiseResolver, resolve);
|
|
1281
|
+
}));
|
|
1282
|
+
__privateGet(this, _midStreamPromise).finally(() => {
|
|
1283
|
+
__privateSet(this, _midStreamPromise, void 0);
|
|
1284
|
+
__privateSet(this, _midStreamPromiseResolver, void 0);
|
|
1285
|
+
});
|
|
1286
|
+
return __privateGet(this, _midStreamPromise);
|
|
1287
|
+
});
|
|
1288
|
+
};
|
|
1084
1289
|
publish_fn = function(messages) {
|
|
1085
1290
|
return __async(this, null, function* () {
|
|
1086
1291
|
__privateSet(this, _messageChain, __privateGet(this, _messageChain).then(
|
|
@@ -1125,8 +1330,33 @@ reset_fn = function(handle) {
|
|
|
1125
1330
|
__privateSet(this, _liveCacheBuster, ``);
|
|
1126
1331
|
__privateSet(this, _shapeHandle, handle);
|
|
1127
1332
|
__privateSet(this, _isUpToDate, false);
|
|
1333
|
+
__privateSet(this, _isMidStream, true);
|
|
1128
1334
|
__privateSet(this, _connected, false);
|
|
1129
1335
|
__privateSet(this, _schema, void 0);
|
|
1336
|
+
__privateSet(this, _activeSnapshotRequests, 0);
|
|
1337
|
+
};
|
|
1338
|
+
fetchSnapshot_fn = function(url, headers) {
|
|
1339
|
+
return __async(this, null, function* () {
|
|
1340
|
+
const response = yield __privateGet(this, _fetchClient2).call(this, url.toString(), { headers });
|
|
1341
|
+
if (!response.ok) {
|
|
1342
|
+
throw new FetchError(
|
|
1343
|
+
response.status,
|
|
1344
|
+
void 0,
|
|
1345
|
+
void 0,
|
|
1346
|
+
Object.fromEntries([...response.headers.entries()]),
|
|
1347
|
+
url.toString()
|
|
1348
|
+
);
|
|
1349
|
+
}
|
|
1350
|
+
const { metadata, data } = yield response.json();
|
|
1351
|
+
const batch = __privateGet(this, _messageParser).parse(
|
|
1352
|
+
JSON.stringify(data),
|
|
1353
|
+
__privateGet(this, _schema)
|
|
1354
|
+
);
|
|
1355
|
+
return {
|
|
1356
|
+
metadata,
|
|
1357
|
+
data: batch
|
|
1358
|
+
};
|
|
1359
|
+
});
|
|
1130
1360
|
};
|
|
1131
1361
|
ShapeStream.Replica = {
|
|
1132
1362
|
FULL: `full`,
|
|
@@ -1148,7 +1378,7 @@ function validateOptions(options) {
|
|
|
1148
1378
|
if (options.signal && !(options.signal instanceof AbortSignal)) {
|
|
1149
1379
|
throw new InvalidSignalError();
|
|
1150
1380
|
}
|
|
1151
|
-
if (options.offset !== void 0 && options.offset !== `-1` && !options.handle) {
|
|
1381
|
+
if (options.offset !== void 0 && options.offset !== `-1` && options.offset !== `now` && !options.handle) {
|
|
1152
1382
|
throw new MissingShapeHandleError();
|
|
1153
1383
|
}
|
|
1154
1384
|
validateParams(options.params);
|
|
@@ -1177,12 +1407,15 @@ function convertWhereParamsToObj(allPgParams) {
|
|
|
1177
1407
|
}
|
|
1178
1408
|
|
|
1179
1409
|
// src/shape.ts
|
|
1180
|
-
var _data, _subscribers2, _status, _error2, _Shape_instances, process_fn, updateShapeStatus_fn, handleError_fn, notify_fn;
|
|
1410
|
+
var _data, _subscribers2, _insertedKeys, _requestedSubSnapshots, _reexecuteSnapshotsPending, _status, _error2, _Shape_instances, process_fn, reexecuteSnapshots_fn, awaitUpToDate_fn, updateShapeStatus_fn, handleError_fn, notify_fn;
|
|
1181
1411
|
var Shape = class {
|
|
1182
1412
|
constructor(stream) {
|
|
1183
1413
|
__privateAdd(this, _Shape_instances);
|
|
1184
1414
|
__privateAdd(this, _data, /* @__PURE__ */ new Map());
|
|
1185
1415
|
__privateAdd(this, _subscribers2, /* @__PURE__ */ new Map());
|
|
1416
|
+
__privateAdd(this, _insertedKeys, /* @__PURE__ */ new Set());
|
|
1417
|
+
__privateAdd(this, _requestedSubSnapshots, /* @__PURE__ */ new Set());
|
|
1418
|
+
__privateAdd(this, _reexecuteSnapshotsPending, false);
|
|
1186
1419
|
__privateAdd(this, _status, `syncing`);
|
|
1187
1420
|
__privateAdd(this, _error2, false);
|
|
1188
1421
|
this.stream = stream;
|
|
@@ -1241,6 +1474,22 @@ var Shape = class {
|
|
|
1241
1474
|
isConnected() {
|
|
1242
1475
|
return this.stream.isConnected();
|
|
1243
1476
|
}
|
|
1477
|
+
/** Current log mode of the underlying stream */
|
|
1478
|
+
get mode() {
|
|
1479
|
+
return this.stream.mode;
|
|
1480
|
+
}
|
|
1481
|
+
/**
|
|
1482
|
+
* Request a snapshot for subset of data. Only available when mode is changes_only.
|
|
1483
|
+
* Returns void; data will be emitted via the stream and processed by this Shape.
|
|
1484
|
+
*/
|
|
1485
|
+
requestSnapshot(params) {
|
|
1486
|
+
return __async(this, null, function* () {
|
|
1487
|
+
const key = JSON.stringify(params);
|
|
1488
|
+
__privateGet(this, _requestedSubSnapshots).add(key);
|
|
1489
|
+
yield __privateMethod(this, _Shape_instances, awaitUpToDate_fn).call(this);
|
|
1490
|
+
yield this.stream.requestSnapshot(params);
|
|
1491
|
+
});
|
|
1492
|
+
}
|
|
1244
1493
|
subscribe(callback) {
|
|
1245
1494
|
const subscriptionId = Math.random();
|
|
1246
1495
|
__privateGet(this, _subscribers2).set(subscriptionId, callback);
|
|
@@ -1257,6 +1506,9 @@ var Shape = class {
|
|
|
1257
1506
|
};
|
|
1258
1507
|
_data = new WeakMap();
|
|
1259
1508
|
_subscribers2 = new WeakMap();
|
|
1509
|
+
_insertedKeys = new WeakMap();
|
|
1510
|
+
_requestedSubSnapshots = new WeakMap();
|
|
1511
|
+
_reexecuteSnapshotsPending = new WeakMap();
|
|
1260
1512
|
_status = new WeakMap();
|
|
1261
1513
|
_error2 = new WeakMap();
|
|
1262
1514
|
_Shape_instances = new WeakSet();
|
|
@@ -1265,33 +1517,93 @@ process_fn = function(messages) {
|
|
|
1265
1517
|
messages.forEach((message) => {
|
|
1266
1518
|
if (isChangeMessage(message)) {
|
|
1267
1519
|
shouldNotify = __privateMethod(this, _Shape_instances, updateShapeStatus_fn).call(this, `syncing`);
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1520
|
+
if (this.mode === `full`) {
|
|
1521
|
+
switch (message.headers.operation) {
|
|
1522
|
+
case `insert`:
|
|
1523
|
+
__privateGet(this, _data).set(message.key, message.value);
|
|
1524
|
+
break;
|
|
1525
|
+
case `update`:
|
|
1526
|
+
__privateGet(this, _data).set(message.key, __spreadValues(__spreadValues({}, __privateGet(this, _data).get(message.key)), message.value));
|
|
1527
|
+
break;
|
|
1528
|
+
case `delete`:
|
|
1529
|
+
__privateGet(this, _data).delete(message.key);
|
|
1530
|
+
break;
|
|
1531
|
+
}
|
|
1532
|
+
} else {
|
|
1533
|
+
switch (message.headers.operation) {
|
|
1534
|
+
case `insert`:
|
|
1535
|
+
__privateGet(this, _insertedKeys).add(message.key);
|
|
1536
|
+
__privateGet(this, _data).set(message.key, message.value);
|
|
1537
|
+
break;
|
|
1538
|
+
case `update`:
|
|
1539
|
+
if (__privateGet(this, _insertedKeys).has(message.key)) {
|
|
1540
|
+
__privateGet(this, _data).set(message.key, __spreadValues(__spreadValues({}, __privateGet(this, _data).get(message.key)), message.value));
|
|
1541
|
+
}
|
|
1542
|
+
break;
|
|
1543
|
+
case `delete`:
|
|
1544
|
+
if (__privateGet(this, _insertedKeys).has(message.key)) {
|
|
1545
|
+
__privateGet(this, _data).delete(message.key);
|
|
1546
|
+
__privateGet(this, _insertedKeys).delete(message.key);
|
|
1547
|
+
}
|
|
1548
|
+
break;
|
|
1549
|
+
}
|
|
1278
1550
|
}
|
|
1279
1551
|
}
|
|
1280
1552
|
if (isControlMessage(message)) {
|
|
1281
1553
|
switch (message.headers.control) {
|
|
1282
1554
|
case `up-to-date`:
|
|
1283
1555
|
shouldNotify = __privateMethod(this, _Shape_instances, updateShapeStatus_fn).call(this, `up-to-date`);
|
|
1556
|
+
if (__privateGet(this, _reexecuteSnapshotsPending)) {
|
|
1557
|
+
__privateSet(this, _reexecuteSnapshotsPending, false);
|
|
1558
|
+
void __privateMethod(this, _Shape_instances, reexecuteSnapshots_fn).call(this);
|
|
1559
|
+
}
|
|
1284
1560
|
break;
|
|
1285
1561
|
case `must-refetch`:
|
|
1286
1562
|
__privateGet(this, _data).clear();
|
|
1563
|
+
__privateGet(this, _insertedKeys).clear();
|
|
1287
1564
|
__privateSet(this, _error2, false);
|
|
1288
1565
|
shouldNotify = __privateMethod(this, _Shape_instances, updateShapeStatus_fn).call(this, `syncing`);
|
|
1566
|
+
__privateSet(this, _reexecuteSnapshotsPending, true);
|
|
1289
1567
|
break;
|
|
1290
1568
|
}
|
|
1291
1569
|
}
|
|
1292
1570
|
});
|
|
1293
1571
|
if (shouldNotify) __privateMethod(this, _Shape_instances, notify_fn).call(this);
|
|
1294
1572
|
};
|
|
1573
|
+
reexecuteSnapshots_fn = function() {
|
|
1574
|
+
return __async(this, null, function* () {
|
|
1575
|
+
yield __privateMethod(this, _Shape_instances, awaitUpToDate_fn).call(this);
|
|
1576
|
+
yield Promise.all(
|
|
1577
|
+
Array.from(__privateGet(this, _requestedSubSnapshots)).map((jsonParams) => __async(this, null, function* () {
|
|
1578
|
+
try {
|
|
1579
|
+
const snapshot = JSON.parse(jsonParams);
|
|
1580
|
+
yield this.stream.requestSnapshot(snapshot);
|
|
1581
|
+
} catch (_) {
|
|
1582
|
+
}
|
|
1583
|
+
}))
|
|
1584
|
+
);
|
|
1585
|
+
});
|
|
1586
|
+
};
|
|
1587
|
+
awaitUpToDate_fn = function() {
|
|
1588
|
+
return __async(this, null, function* () {
|
|
1589
|
+
if (this.stream.isUpToDate) return;
|
|
1590
|
+
yield new Promise((resolve) => {
|
|
1591
|
+
const check = () => {
|
|
1592
|
+
if (this.stream.isUpToDate) {
|
|
1593
|
+
clearInterval(interval);
|
|
1594
|
+
unsub();
|
|
1595
|
+
resolve();
|
|
1596
|
+
}
|
|
1597
|
+
};
|
|
1598
|
+
const interval = setInterval(check, 10);
|
|
1599
|
+
const unsub = this.stream.subscribe(
|
|
1600
|
+
() => check(),
|
|
1601
|
+
() => check()
|
|
1602
|
+
);
|
|
1603
|
+
check();
|
|
1604
|
+
});
|
|
1605
|
+
});
|
|
1606
|
+
};
|
|
1295
1607
|
updateShapeStatus_fn = function(status) {
|
|
1296
1608
|
const stateChanged = __privateGet(this, _status) !== status;
|
|
1297
1609
|
__privateSet(this, _status, status);
|
|
@@ -1316,6 +1628,7 @@ export {
|
|
|
1316
1628
|
ShapeStream,
|
|
1317
1629
|
isChangeMessage,
|
|
1318
1630
|
isControlMessage,
|
|
1631
|
+
isVisibleInSnapshot,
|
|
1319
1632
|
resolveValue
|
|
1320
1633
|
};
|
|
1321
1634
|
//# sourceMappingURL=index.mjs.map
|