@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.
@@ -476,6 +476,12 @@ function getOffset(message) {
476
476
  const lsn = message.headers.global_last_seen_lsn;
477
477
  return lsn ? `${lsn}_0` : void 0;
478
478
  }
479
+ function bigintReplacer(_key, value) {
480
+ return typeof value === `bigint` ? value.toString() : value;
481
+ }
482
+ function bigintSafeStringify(value) {
483
+ return JSON.stringify(value, bigintReplacer);
484
+ }
479
485
  function isVisibleInSnapshot(txid, snapshot) {
480
486
  const xid = BigInt(txid);
481
487
  const xmin = BigInt(snapshot.xmin);
@@ -646,6 +652,12 @@ function createFetchWithChunkBuffer(fetchClient, prefetchOptions = ChunkPrefetch
646
652
  let prefetchQueue;
647
653
  const prefetchClient = async (...args) => {
648
654
  const url = args[0].toString();
655
+ const method = getRequestMethod(args[0], args[1]);
656
+ if (method !== `GET`) {
657
+ prefetchQueue == null ? void 0 : prefetchQueue.abort();
658
+ prefetchQueue = void 0;
659
+ return fetchClient(...args);
660
+ }
649
661
  const prefetchedRequest = prefetchQueue == null ? void 0 : prefetchQueue.consume(...args);
650
662
  if (prefetchedRequest) {
651
663
  return prefetchedRequest;
@@ -815,6 +827,15 @@ function chainAborter(aborter, sourceSignal) {
815
827
  }
816
828
  function noop() {
817
829
  }
830
+ function getRequestMethod(input, init) {
831
+ if (init == null ? void 0 : init.method) {
832
+ return init.method.toUpperCase();
833
+ }
834
+ if (typeof Request !== `undefined` && input instanceof Request) {
835
+ return input.method.toUpperCase();
836
+ }
837
+ return `GET`;
838
+ }
818
839
 
819
840
  // src/expression-compiler.ts
820
841
  function compileExpression(expr, columnMapper) {
@@ -1491,6 +1512,12 @@ var FetchingState = class extends ActiveState {
1491
1512
  const staleResult = this.checkStaleResponse(input);
1492
1513
  if (staleResult) return staleResult;
1493
1514
  const shared = this.parseResponseFields(input);
1515
+ if (input.status === 204) {
1516
+ return {
1517
+ action: `accepted`,
1518
+ state: new LiveState(shared, { sseFallbackToLongPolling: true })
1519
+ };
1520
+ }
1494
1521
  return { action: `accepted`, state: new SyncingState(shared) };
1495
1522
  }
1496
1523
  canEnterReplayMode() {
@@ -1720,6 +1747,13 @@ var PausedState = class _PausedState extends ShapeStreamState {
1720
1747
  get replayCursor() {
1721
1748
  return this.previousState.replayCursor;
1722
1749
  }
1750
+ handleResponseMetadata(input) {
1751
+ const transition = this.previousState.handleResponseMetadata(input);
1752
+ if (transition.action === `accepted`) {
1753
+ return { action: `accepted`, state: new _PausedState(transition.state) };
1754
+ }
1755
+ return transition;
1756
+ }
1723
1757
  withHandle(handle) {
1724
1758
  return new _PausedState(this.previousState.withHandle(handle));
1725
1759
  }
@@ -2110,7 +2144,7 @@ var ShapeStream = class {
2110
2144
  );
2111
2145
  }, 3e4);
2112
2146
  try {
2113
- const { metadata, data } = await this.fetchSnapshot(opts);
2147
+ const { metadata, data, responseOffset, responseHandle } = await this.fetchSnapshot(opts);
2114
2148
  const dataWithEndBoundary = data.concat([
2115
2149
  { headers: __spreadValues({ control: `snapshot-end` }, metadata) },
2116
2150
  { headers: __spreadValues({ control: `subset-end` }, opts) }
@@ -2120,6 +2154,25 @@ var ShapeStream = class {
2120
2154
  new Set(data.map((message) => message.key))
2121
2155
  );
2122
2156
  __privateMethod(this, _ShapeStream_instances, onMessages_fn).call(this, dataWithEndBoundary, false);
2157
+ if (responseOffset !== null || responseHandle !== null) {
2158
+ const transition = __privateGet(this, _syncState).handleResponseMetadata({
2159
+ status: 200,
2160
+ responseHandle,
2161
+ responseOffset,
2162
+ responseCursor: null,
2163
+ expiredHandle: null,
2164
+ now: Date.now(),
2165
+ maxStaleCacheRetries: __privateGet(this, _maxStaleCacheRetries),
2166
+ createCacheBuster: () => `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`
2167
+ });
2168
+ if (transition.action === `accepted`) {
2169
+ __privateSet(this, _syncState, transition.state);
2170
+ } else {
2171
+ console.warn(
2172
+ `[Electric] Snapshot response metadata was not accepted by state "${__privateGet(this, _syncState).kind}" (action: ${transition.action}). Stream offset was not advanced from snapshot.`
2173
+ );
2174
+ }
2175
+ }
2123
2176
  return {
2124
2177
  metadata,
2125
2178
  data
@@ -2138,7 +2191,7 @@ var ShapeStream = class {
2138
2191
  * `subsetMethod: 'POST'` on the stream to send parameters in the request body instead.
2139
2192
  *
2140
2193
  * @param opts - The options for the snapshot request.
2141
- * @returns The metadata and the data for the snapshot.
2194
+ * @returns The metadata, data, and the response's offset/handle for state advancement.
2142
2195
  */
2143
2196
  async fetchSnapshot(opts) {
2144
2197
  var _a, _b, _c;
@@ -2154,7 +2207,7 @@ var ShapeStream = class {
2154
2207
  headers: __spreadProps(__spreadValues({}, result.requestHeaders), {
2155
2208
  "Content-Type": `application/json`
2156
2209
  }),
2157
- body: JSON.stringify(__privateMethod(this, _ShapeStream_instances, buildSubsetBody_fn).call(this, opts))
2210
+ body: bigintSafeStringify(__privateMethod(this, _ShapeStream_instances, buildSubsetBody_fn).call(this, opts))
2158
2211
  };
2159
2212
  } else {
2160
2213
  const result = await __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, this.options.url, true, opts);
@@ -2189,7 +2242,9 @@ var ShapeStream = class {
2189
2242
  rawData,
2190
2243
  schema
2191
2244
  );
2192
- return { metadata, data };
2245
+ const responseOffset = response.headers.get(CHUNK_LAST_OFFSET_HEADER) || null;
2246
+ const responseHandle = response.headers.get(SHAPE_HANDLE_HEADER);
2247
+ return { metadata, data, responseOffset, responseHandle };
2193
2248
  }
2194
2249
  };
2195
2250
  _error = new WeakMap();
@@ -2402,7 +2457,7 @@ constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
2402
2457
  if (subsetParams.params)
2403
2458
  fetchUrl.searchParams.set(
2404
2459
  SUBSET_PARAM_WHERE_PARAMS,
2405
- JSON.stringify(subsetParams.params)
2460
+ bigintSafeStringify(subsetParams.params)
2406
2461
  );
2407
2462
  if (subsetParams.limit)
2408
2463
  setQueryParam(fetchUrl, SUBSET_PARAM_LIMIT, subsetParams.limit);
@@ -2581,7 +2636,7 @@ requestShapeLongPoll_fn = async function(opts) {
2581
2636
  const messages = res || `[]`;
2582
2637
  const batch = __privateGet(this, _messageParser).parse(messages, schema);
2583
2638
  if (!Array.isArray(batch)) {
2584
- const preview = (_a = JSON.stringify(batch)) == null ? void 0 : _a.slice(0, 200);
2639
+ const preview = (_a = bigintSafeStringify(batch)) == null ? void 0 : _a.slice(0, 200);
2585
2640
  throw new FetchError(
2586
2641
  response.status,
2587
2642
  `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}`,
@@ -2639,7 +2694,9 @@ requestShapeSSE_fn = async function(opts) {
2639
2694
  if (requestAbortController.signal.aborted) {
2640
2695
  throw new FetchBackoffAbortError();
2641
2696
  }
2642
- throw error;
2697
+ if (error instanceof FetchError || error instanceof StaleCacheError || error instanceof MissingHeadersError) {
2698
+ throw error;
2699
+ }
2643
2700
  } finally {
2644
2701
  const connectionDuration = Date.now() - __privateGet(this, _lastSseConnectionStartTime);
2645
2702
  const wasAborted = requestAbortController.signal.aborted;
@@ -2943,7 +3000,7 @@ var Shape = class {
2943
3000
  * Returns void; data will be emitted via the stream and processed by this Shape.
2944
3001
  */
2945
3002
  async requestSnapshot(params) {
2946
- const key = JSON.stringify(params);
3003
+ const key = bigintSafeStringify(params);
2947
3004
  __privateGet(this, _requestedSubSnapshots).add(key);
2948
3005
  await __privateMethod(this, _Shape_instances, awaitUpToDate_fn).call(this);
2949
3006
  await this.stream.requestSnapshot(params);