@electric-sql/client 1.5.6 → 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/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 data for the snapshot.
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
 
@@ -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);
@@ -1704,6 +1710,13 @@ var PausedState = class _PausedState extends ShapeStreamState {
1704
1710
  get replayCursor() {
1705
1711
  return this.previousState.replayCursor;
1706
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
+ }
1707
1720
  withHandle(handle) {
1708
1721
  return new _PausedState(this.previousState.withHandle(handle));
1709
1722
  }
@@ -2094,7 +2107,7 @@ var ShapeStream = class {
2094
2107
  );
2095
2108
  }, 3e4);
2096
2109
  try {
2097
- const { metadata, data } = await this.fetchSnapshot(opts);
2110
+ const { metadata, data, responseOffset, responseHandle } = await this.fetchSnapshot(opts);
2098
2111
  const dataWithEndBoundary = data.concat([
2099
2112
  { headers: __spreadValues({ control: `snapshot-end` }, metadata) },
2100
2113
  { headers: __spreadValues({ control: `subset-end` }, opts) }
@@ -2104,6 +2117,25 @@ var ShapeStream = class {
2104
2117
  new Set(data.map((message) => message.key))
2105
2118
  );
2106
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
+ }
2107
2139
  return {
2108
2140
  metadata,
2109
2141
  data
@@ -2122,7 +2154,7 @@ var ShapeStream = class {
2122
2154
  * `subsetMethod: 'POST'` on the stream to send parameters in the request body instead.
2123
2155
  *
2124
2156
  * @param opts - The options for the snapshot request.
2125
- * @returns The metadata and the data for the snapshot.
2157
+ * @returns The metadata, data, and the response's offset/handle for state advancement.
2126
2158
  */
2127
2159
  async fetchSnapshot(opts) {
2128
2160
  var _a, _b, _c;
@@ -2138,7 +2170,7 @@ var ShapeStream = class {
2138
2170
  headers: __spreadProps(__spreadValues({}, result.requestHeaders), {
2139
2171
  "Content-Type": `application/json`
2140
2172
  }),
2141
- body: JSON.stringify(__privateMethod(this, _ShapeStream_instances, buildSubsetBody_fn).call(this, opts))
2173
+ body: bigintSafeStringify(__privateMethod(this, _ShapeStream_instances, buildSubsetBody_fn).call(this, opts))
2142
2174
  };
2143
2175
  } else {
2144
2176
  const result = await __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, this.options.url, true, opts);
@@ -2173,7 +2205,9 @@ var ShapeStream = class {
2173
2205
  rawData,
2174
2206
  schema
2175
2207
  );
2176
- return { metadata, data };
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 };
2177
2211
  }
2178
2212
  };
2179
2213
  _error = new WeakMap();
@@ -2386,7 +2420,7 @@ constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
2386
2420
  if (subsetParams.params)
2387
2421
  fetchUrl.searchParams.set(
2388
2422
  SUBSET_PARAM_WHERE_PARAMS,
2389
- JSON.stringify(subsetParams.params)
2423
+ bigintSafeStringify(subsetParams.params)
2390
2424
  );
2391
2425
  if (subsetParams.limit)
2392
2426
  setQueryParam(fetchUrl, SUBSET_PARAM_LIMIT, subsetParams.limit);
@@ -2565,7 +2599,7 @@ requestShapeLongPoll_fn = async function(opts) {
2565
2599
  const messages = res || `[]`;
2566
2600
  const batch = __privateGet(this, _messageParser).parse(messages, schema);
2567
2601
  if (!Array.isArray(batch)) {
2568
- const preview = (_a = JSON.stringify(batch)) == null ? void 0 : _a.slice(0, 200);
2602
+ const preview = (_a = bigintSafeStringify(batch)) == null ? void 0 : _a.slice(0, 200);
2569
2603
  throw new FetchError(
2570
2604
  response.status,
2571
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}`,
@@ -2929,7 +2963,7 @@ var Shape = class {
2929
2963
  * Returns void; data will be emitted via the stream and processed by this Shape.
2930
2964
  */
2931
2965
  async requestSnapshot(params) {
2932
- const key = JSON.stringify(params);
2966
+ const key = bigintSafeStringify(params);
2933
2967
  __privateGet(this, _requestedSubSnapshots).add(key);
2934
2968
  await __privateMethod(this, _Shape_instances, awaitUpToDate_fn).call(this);
2935
2969
  await this.stream.requestSnapshot(params);