@electric-sql/client 1.5.5 → 1.5.7
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 +65 -8
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +4 -2
- package/dist/index.browser.mjs +4 -4
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.legacy-esm.js +65 -8
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +65 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +56 -8
- package/src/fetch.ts +26 -0
- package/src/helpers.ts +15 -0
- package/src/shape-stream-state.ts +23 -0
- package/src/shape.ts +6 -2
- package/src/types.ts +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -73,7 +73,7 @@ type SubsetParams = {
|
|
|
73
73
|
/** Legacy string format WHERE clause */
|
|
74
74
|
where?: string;
|
|
75
75
|
/** Positional parameter values for WHERE clause */
|
|
76
|
-
params?: Record<string, string>;
|
|
76
|
+
params?: Record<string, string | bigint | number>;
|
|
77
77
|
/** Maximum number of rows to return */
|
|
78
78
|
limit?: number;
|
|
79
79
|
/** Number of rows to skip */
|
|
@@ -783,11 +783,13 @@ declare class ShapeStream<T extends Row<unknown> = Row> implements ShapeStreamIn
|
|
|
783
783
|
* `subsetMethod: 'POST'` on the stream to send parameters in the request body instead.
|
|
784
784
|
*
|
|
785
785
|
* @param opts - The options for the snapshot request.
|
|
786
|
-
* @returns The metadata and the
|
|
786
|
+
* @returns The metadata, data, and the response's offset/handle for state advancement.
|
|
787
787
|
*/
|
|
788
788
|
fetchSnapshot(opts: SubsetParams): Promise<{
|
|
789
789
|
metadata: SnapshotMetadata;
|
|
790
790
|
data: Array<ChangeMessage<T>>;
|
|
791
|
+
responseOffset: Offset | null;
|
|
792
|
+
responseHandle: string | null;
|
|
791
793
|
}>;
|
|
792
794
|
}
|
|
793
795
|
|
package/dist/index.legacy-esm.js
CHANGED
|
@@ -439,6 +439,12 @@ function getOffset(message) {
|
|
|
439
439
|
const lsn = message.headers.global_last_seen_lsn;
|
|
440
440
|
return lsn ? `${lsn}_0` : void 0;
|
|
441
441
|
}
|
|
442
|
+
function bigintReplacer(_key, value) {
|
|
443
|
+
return typeof value === `bigint` ? value.toString() : value;
|
|
444
|
+
}
|
|
445
|
+
function bigintSafeStringify(value) {
|
|
446
|
+
return JSON.stringify(value, bigintReplacer);
|
|
447
|
+
}
|
|
442
448
|
function isVisibleInSnapshot(txid, snapshot) {
|
|
443
449
|
const xid = BigInt(txid);
|
|
444
450
|
const xmin = BigInt(snapshot.xmin);
|
|
@@ -609,6 +615,12 @@ function createFetchWithChunkBuffer(fetchClient, prefetchOptions = ChunkPrefetch
|
|
|
609
615
|
let prefetchQueue;
|
|
610
616
|
const prefetchClient = async (...args) => {
|
|
611
617
|
const url = args[0].toString();
|
|
618
|
+
const method = getRequestMethod(args[0], args[1]);
|
|
619
|
+
if (method !== `GET`) {
|
|
620
|
+
prefetchQueue == null ? void 0 : prefetchQueue.abort();
|
|
621
|
+
prefetchQueue = void 0;
|
|
622
|
+
return fetchClient(...args);
|
|
623
|
+
}
|
|
612
624
|
const prefetchedRequest = prefetchQueue == null ? void 0 : prefetchQueue.consume(...args);
|
|
613
625
|
if (prefetchedRequest) {
|
|
614
626
|
return prefetchedRequest;
|
|
@@ -778,6 +790,15 @@ function chainAborter(aborter, sourceSignal) {
|
|
|
778
790
|
}
|
|
779
791
|
function noop() {
|
|
780
792
|
}
|
|
793
|
+
function getRequestMethod(input, init) {
|
|
794
|
+
if (init == null ? void 0 : init.method) {
|
|
795
|
+
return init.method.toUpperCase();
|
|
796
|
+
}
|
|
797
|
+
if (typeof Request !== `undefined` && input instanceof Request) {
|
|
798
|
+
return input.method.toUpperCase();
|
|
799
|
+
}
|
|
800
|
+
return `GET`;
|
|
801
|
+
}
|
|
781
802
|
|
|
782
803
|
// src/expression-compiler.ts
|
|
783
804
|
function compileExpression(expr, columnMapper) {
|
|
@@ -1454,6 +1475,12 @@ var FetchingState = class extends ActiveState {
|
|
|
1454
1475
|
const staleResult = this.checkStaleResponse(input);
|
|
1455
1476
|
if (staleResult) return staleResult;
|
|
1456
1477
|
const shared = this.parseResponseFields(input);
|
|
1478
|
+
if (input.status === 204) {
|
|
1479
|
+
return {
|
|
1480
|
+
action: `accepted`,
|
|
1481
|
+
state: new LiveState(shared, { sseFallbackToLongPolling: true })
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1457
1484
|
return { action: `accepted`, state: new SyncingState(shared) };
|
|
1458
1485
|
}
|
|
1459
1486
|
canEnterReplayMode() {
|
|
@@ -1683,6 +1710,13 @@ var PausedState = class _PausedState extends ShapeStreamState {
|
|
|
1683
1710
|
get replayCursor() {
|
|
1684
1711
|
return this.previousState.replayCursor;
|
|
1685
1712
|
}
|
|
1713
|
+
handleResponseMetadata(input) {
|
|
1714
|
+
const transition = this.previousState.handleResponseMetadata(input);
|
|
1715
|
+
if (transition.action === `accepted`) {
|
|
1716
|
+
return { action: `accepted`, state: new _PausedState(transition.state) };
|
|
1717
|
+
}
|
|
1718
|
+
return transition;
|
|
1719
|
+
}
|
|
1686
1720
|
withHandle(handle) {
|
|
1687
1721
|
return new _PausedState(this.previousState.withHandle(handle));
|
|
1688
1722
|
}
|
|
@@ -2073,7 +2107,7 @@ var ShapeStream = class {
|
|
|
2073
2107
|
);
|
|
2074
2108
|
}, 3e4);
|
|
2075
2109
|
try {
|
|
2076
|
-
const { metadata, data } = await this.fetchSnapshot(opts);
|
|
2110
|
+
const { metadata, data, responseOffset, responseHandle } = await this.fetchSnapshot(opts);
|
|
2077
2111
|
const dataWithEndBoundary = data.concat([
|
|
2078
2112
|
{ headers: __spreadValues({ control: `snapshot-end` }, metadata) },
|
|
2079
2113
|
{ headers: __spreadValues({ control: `subset-end` }, opts) }
|
|
@@ -2083,6 +2117,25 @@ var ShapeStream = class {
|
|
|
2083
2117
|
new Set(data.map((message) => message.key))
|
|
2084
2118
|
);
|
|
2085
2119
|
__privateMethod(this, _ShapeStream_instances, onMessages_fn).call(this, dataWithEndBoundary, false);
|
|
2120
|
+
if (responseOffset !== null || responseHandle !== null) {
|
|
2121
|
+
const transition = __privateGet(this, _syncState).handleResponseMetadata({
|
|
2122
|
+
status: 200,
|
|
2123
|
+
responseHandle,
|
|
2124
|
+
responseOffset,
|
|
2125
|
+
responseCursor: null,
|
|
2126
|
+
expiredHandle: null,
|
|
2127
|
+
now: Date.now(),
|
|
2128
|
+
maxStaleCacheRetries: __privateGet(this, _maxStaleCacheRetries),
|
|
2129
|
+
createCacheBuster: () => `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`
|
|
2130
|
+
});
|
|
2131
|
+
if (transition.action === `accepted`) {
|
|
2132
|
+
__privateSet(this, _syncState, transition.state);
|
|
2133
|
+
} else {
|
|
2134
|
+
console.warn(
|
|
2135
|
+
`[Electric] Snapshot response metadata was not accepted by state "${__privateGet(this, _syncState).kind}" (action: ${transition.action}). Stream offset was not advanced from snapshot.`
|
|
2136
|
+
);
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2086
2139
|
return {
|
|
2087
2140
|
metadata,
|
|
2088
2141
|
data
|
|
@@ -2101,7 +2154,7 @@ var ShapeStream = class {
|
|
|
2101
2154
|
* `subsetMethod: 'POST'` on the stream to send parameters in the request body instead.
|
|
2102
2155
|
*
|
|
2103
2156
|
* @param opts - The options for the snapshot request.
|
|
2104
|
-
* @returns The metadata and the
|
|
2157
|
+
* @returns The metadata, data, and the response's offset/handle for state advancement.
|
|
2105
2158
|
*/
|
|
2106
2159
|
async fetchSnapshot(opts) {
|
|
2107
2160
|
var _a, _b, _c;
|
|
@@ -2117,7 +2170,7 @@ var ShapeStream = class {
|
|
|
2117
2170
|
headers: __spreadProps(__spreadValues({}, result.requestHeaders), {
|
|
2118
2171
|
"Content-Type": `application/json`
|
|
2119
2172
|
}),
|
|
2120
|
-
body:
|
|
2173
|
+
body: bigintSafeStringify(__privateMethod(this, _ShapeStream_instances, buildSubsetBody_fn).call(this, opts))
|
|
2121
2174
|
};
|
|
2122
2175
|
} else {
|
|
2123
2176
|
const result = await __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, this.options.url, true, opts);
|
|
@@ -2152,7 +2205,9 @@ var ShapeStream = class {
|
|
|
2152
2205
|
rawData,
|
|
2153
2206
|
schema
|
|
2154
2207
|
);
|
|
2155
|
-
|
|
2208
|
+
const responseOffset = response.headers.get(CHUNK_LAST_OFFSET_HEADER) || null;
|
|
2209
|
+
const responseHandle = response.headers.get(SHAPE_HANDLE_HEADER);
|
|
2210
|
+
return { metadata, data, responseOffset, responseHandle };
|
|
2156
2211
|
}
|
|
2157
2212
|
};
|
|
2158
2213
|
_error = new WeakMap();
|
|
@@ -2365,7 +2420,7 @@ constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
|
|
|
2365
2420
|
if (subsetParams.params)
|
|
2366
2421
|
fetchUrl.searchParams.set(
|
|
2367
2422
|
SUBSET_PARAM_WHERE_PARAMS,
|
|
2368
|
-
|
|
2423
|
+
bigintSafeStringify(subsetParams.params)
|
|
2369
2424
|
);
|
|
2370
2425
|
if (subsetParams.limit)
|
|
2371
2426
|
setQueryParam(fetchUrl, SUBSET_PARAM_LIMIT, subsetParams.limit);
|
|
@@ -2544,7 +2599,7 @@ requestShapeLongPoll_fn = async function(opts) {
|
|
|
2544
2599
|
const messages = res || `[]`;
|
|
2545
2600
|
const batch = __privateGet(this, _messageParser).parse(messages, schema);
|
|
2546
2601
|
if (!Array.isArray(batch)) {
|
|
2547
|
-
const preview = (_a =
|
|
2602
|
+
const preview = (_a = bigintSafeStringify(batch)) == null ? void 0 : _a.slice(0, 200);
|
|
2548
2603
|
throw new FetchError(
|
|
2549
2604
|
response.status,
|
|
2550
2605
|
`Received non-array response body from shape endpoint. This may indicate a proxy or CDN is returning an unexpected response. Expected a JSON array, got ${typeof batch}: ${preview}`,
|
|
@@ -2602,7 +2657,9 @@ requestShapeSSE_fn = async function(opts) {
|
|
|
2602
2657
|
if (requestAbortController.signal.aborted) {
|
|
2603
2658
|
throw new FetchBackoffAbortError();
|
|
2604
2659
|
}
|
|
2605
|
-
|
|
2660
|
+
if (error instanceof FetchError || error instanceof StaleCacheError || error instanceof MissingHeadersError) {
|
|
2661
|
+
throw error;
|
|
2662
|
+
}
|
|
2606
2663
|
} finally {
|
|
2607
2664
|
const connectionDuration = Date.now() - __privateGet(this, _lastSseConnectionStartTime);
|
|
2608
2665
|
const wasAborted = requestAbortController.signal.aborted;
|
|
@@ -2906,7 +2963,7 @@ var Shape = class {
|
|
|
2906
2963
|
* Returns void; data will be emitted via the stream and processed by this Shape.
|
|
2907
2964
|
*/
|
|
2908
2965
|
async requestSnapshot(params) {
|
|
2909
|
-
const key =
|
|
2966
|
+
const key = bigintSafeStringify(params);
|
|
2910
2967
|
__privateGet(this, _requestedSubSnapshots).add(key);
|
|
2911
2968
|
await __privateMethod(this, _Shape_instances, awaitUpToDate_fn).call(this);
|
|
2912
2969
|
await this.stream.requestSnapshot(params);
|