@electric-sql/client 1.1.4 → 1.1.5

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
@@ -368,16 +368,14 @@ interface ShapeStreamInterface<T extends Row<unknown> = Row> {
368
368
  error?: unknown;
369
369
  mode: LogMode;
370
370
  forceDisconnectAndRefresh(): Promise<void>;
371
- requestSnapshot(params: {
372
- where?: string;
373
- params?: Record<string, string>;
374
- limit: number;
375
- offset?: number;
376
- orderBy: string;
377
- }): Promise<{
371
+ requestSnapshot(params: SubsetParams): Promise<{
378
372
  metadata: SnapshotMetadata;
379
373
  data: Array<Message<T>>;
380
374
  }>;
375
+ fetchSnapshot(opts: SubsetParams): Promise<{
376
+ metadata: SnapshotMetadata;
377
+ data: Array<ChangeMessage<T>>;
378
+ }>;
381
379
  }
382
380
  /**
383
381
  * Reads updates to a shape from Electric using HTTP requests and long polling or
@@ -451,7 +449,7 @@ declare class ShapeStream<T extends Row<unknown> = Row> implements ShapeStreamIn
451
449
  */
452
450
  forceDisconnectAndRefresh(): Promise<void>;
453
451
  /**
454
- * Request a snapshot for subset of data.
452
+ * Request a snapshot for subset of data and inject it into the subscribed data stream.
455
453
  *
456
454
  * Only available when mode is `changes_only`.
457
455
  * Returns the insertion point & the data, but more importantly injects the data
@@ -468,6 +466,17 @@ declare class ShapeStream<T extends Row<unknown> = Row> implements ShapeStreamIn
468
466
  metadata: SnapshotMetadata;
469
467
  data: Array<ChangeMessage<T>>;
470
468
  }>;
469
+ /**
470
+ * Fetch a snapshot for subset of data.
471
+ * Returns the metadata and the data, but does not inject it into the subscribed data stream.
472
+ *
473
+ * @param opts - The options for the snapshot request.
474
+ * @returns The metadata and the data for the snapshot.
475
+ */
476
+ fetchSnapshot(opts: SubsetParams): Promise<{
477
+ metadata: SnapshotMetadata;
478
+ data: Array<ChangeMessage<T>>;
479
+ }>;
471
480
  }
472
481
 
473
482
  type ShapeData<T extends Row<unknown> = Row> = Map<string, T>;
@@ -203,15 +203,37 @@ var MessageParser = class {
203
203
  parse(messages, schema) {
204
204
  return JSON.parse(messages, (key, value) => {
205
205
  if ((key === `value` || key === `old_value`) && typeof value === `object` && value !== null) {
206
- const row = value;
207
- Object.keys(row).forEach((key2) => {
208
- row[key2] = this.parseRow(key2, row[key2], schema);
209
- });
210
- if (this.transformer) value = this.transformer(value);
206
+ return this.transformMessageValue(value, schema);
211
207
  }
212
208
  return value;
213
209
  });
214
210
  }
211
+ /**
212
+ * Parse an array of ChangeMessages from a snapshot response.
213
+ * Applies type parsing and transformations to the value and old_value properties.
214
+ */
215
+ parseSnapshotData(messages, schema) {
216
+ return messages.map((message) => {
217
+ const msg = message;
218
+ if (msg.value && typeof msg.value === `object` && msg.value !== null) {
219
+ msg.value = this.transformMessageValue(msg.value, schema);
220
+ }
221
+ if (msg.old_value && typeof msg.old_value === `object` && msg.old_value !== null) {
222
+ msg.old_value = this.transformMessageValue(msg.old_value, schema);
223
+ }
224
+ return msg;
225
+ });
226
+ }
227
+ /**
228
+ * Transform a message value or old_value object by parsing its columns.
229
+ */
230
+ transformMessageValue(value, schema) {
231
+ const row = value;
232
+ Object.keys(row).forEach((key) => {
233
+ row[key] = this.parseRow(key, row[key], schema);
234
+ });
235
+ return this.transformer ? this.transformer(row) : row;
236
+ }
215
237
  // Parses the message values using the provided parser based on the schema information
216
238
  parseRow(key, value, schema) {
217
239
  var _b;
@@ -751,7 +773,7 @@ function canonicalShapeKey(url) {
751
773
  cleanUrl.searchParams.sort();
752
774
  return cleanUrl.toString();
753
775
  }
754
- 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, _lastSseConnectionStartTime, _minSseConnectionDuration, _consecutiveShortSseConnections, _maxShortSseConnections, _sseFallbackToLongPolling, _sseBackoffBaseDelay, _sseBackoffMaxDelay, _unsubscribeFromVisibilityChanges, _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;
776
+ 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, _lastSseConnectionStartTime, _minSseConnectionDuration, _consecutiveShortSseConnections, _maxShortSseConnections, _sseFallbackToLongPolling, _sseBackoffBaseDelay, _sseBackoffMaxDelay, _unsubscribeFromVisibilityChanges, _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;
755
777
  var ShapeStream = class {
756
778
  constructor(options) {
757
779
  __privateAdd(this, _ShapeStream_instances);
@@ -896,7 +918,7 @@ var ShapeStream = class {
896
918
  __privateSet(this, _isRefreshing, false);
897
919
  }
898
920
  /**
899
- * Request a snapshot for subset of data.
921
+ * Request a snapshot for subset of data and inject it into the subscribed data stream.
900
922
  *
901
923
  * Only available when mode is `changes_only`.
902
924
  * Returns the insertion point & the data, but more importantly injects the data
@@ -922,8 +944,7 @@ var ShapeStream = class {
922
944
  if (__privateGet(this, _activeSnapshotRequests) === 1) {
923
945
  __privateMethod(this, _ShapeStream_instances, pause_fn).call(this);
924
946
  }
925
- const { fetchUrl, requestHeaders } = await __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, this.options.url, true, opts);
926
- const { metadata, data } = await __privateMethod(this, _ShapeStream_instances, fetchSnapshot_fn).call(this, fetchUrl, requestHeaders);
947
+ const { metadata, data } = await this.fetchSnapshot(opts);
927
948
  const dataWithEndBoundary = data.concat([
928
949
  { headers: __spreadValues({ control: `snapshot-end` }, metadata) }
929
950
  ]);
@@ -943,6 +964,42 @@ var ShapeStream = class {
943
964
  }
944
965
  }
945
966
  }
967
+ /**
968
+ * Fetch a snapshot for subset of data.
969
+ * Returns the metadata and the data, but does not inject it into the subscribed data stream.
970
+ *
971
+ * @param opts - The options for the snapshot request.
972
+ * @returns The metadata and the data for the snapshot.
973
+ */
974
+ async fetchSnapshot(opts) {
975
+ var _a;
976
+ const { fetchUrl, requestHeaders } = await __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, this.options.url, true, opts);
977
+ const response = await __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
978
+ headers: requestHeaders
979
+ });
980
+ if (!response.ok) {
981
+ throw new FetchError(
982
+ response.status,
983
+ void 0,
984
+ void 0,
985
+ Object.fromEntries([...response.headers.entries()]),
986
+ fetchUrl.toString()
987
+ );
988
+ }
989
+ const schema = (_a = __privateGet(this, _schema)) != null ? _a : getSchemaFromHeaders(response.headers, {
990
+ required: true,
991
+ url: fetchUrl.toString()
992
+ });
993
+ const { metadata, data: rawData } = await response.json();
994
+ const data = __privateGet(this, _messageParser).parseSnapshotData(
995
+ rawData,
996
+ schema
997
+ );
998
+ return {
999
+ metadata,
1000
+ data
1001
+ };
1002
+ }
946
1003
  };
947
1004
  _error = new WeakMap();
948
1005
  _fetchClient2 = new WeakMap();
@@ -1112,7 +1169,8 @@ constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
1112
1169
  }
1113
1170
  fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
1114
1171
  fetchUrl.searchParams.set(LOG_MODE_QUERY_PARAM, __privateGet(this, _mode));
1115
- if (__privateGet(this, _isUpToDate)) {
1172
+ const isSnapshotRequest = subsetParams !== void 0;
1173
+ if (__privateGet(this, _isUpToDate) && !isSnapshotRequest) {
1116
1174
  if (!__privateGet(this, _isRefreshing) && !resumingFromPause) {
1117
1175
  fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
1118
1176
  }
@@ -1165,11 +1223,7 @@ onInitialResponse_fn = async function(response) {
1165
1223
  if (liveCacheBuster) {
1166
1224
  __privateSet(this, _liveCacheBuster, liveCacheBuster);
1167
1225
  }
1168
- const getSchema = () => {
1169
- const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
1170
- return schemaHeader ? JSON.parse(schemaHeader) : {};
1171
- };
1172
- __privateSet(this, _schema, (_a = __privateGet(this, _schema)) != null ? _a : getSchema());
1226
+ __privateSet(this, _schema, (_a = __privateGet(this, _schema)) != null ? _a : getSchemaFromHeaders(headers));
1173
1227
  if (status === 204) {
1174
1228
  __privateSet(this, _lastSyncedAt, Date.now());
1175
1229
  }
@@ -1382,31 +1436,20 @@ reset_fn = function(handle) {
1382
1436
  __privateSet(this, _consecutiveShortSseConnections, 0);
1383
1437
  __privateSet(this, _sseFallbackToLongPolling, false);
1384
1438
  };
1385
- fetchSnapshot_fn = async function(url, headers) {
1386
- const response = await __privateGet(this, _fetchClient2).call(this, url.toString(), { headers });
1387
- if (!response.ok) {
1388
- throw new FetchError(
1389
- response.status,
1390
- void 0,
1391
- void 0,
1392
- Object.fromEntries([...response.headers.entries()]),
1393
- url.toString()
1394
- );
1395
- }
1396
- const { metadata, data } = await response.json();
1397
- const batch = __privateGet(this, _messageParser).parse(
1398
- JSON.stringify(data),
1399
- __privateGet(this, _schema)
1400
- );
1401
- return {
1402
- metadata,
1403
- data: batch
1404
- };
1405
- };
1406
1439
  ShapeStream.Replica = {
1407
1440
  FULL: `full`,
1408
1441
  DEFAULT: `default`
1409
1442
  };
1443
+ function getSchemaFromHeaders(headers, options) {
1444
+ const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
1445
+ if (!schemaHeader) {
1446
+ if ((options == null ? void 0 : options.required) && (options == null ? void 0 : options.url)) {
1447
+ throw new MissingHeadersError(options.url, [SHAPE_SCHEMA_HEADER]);
1448
+ }
1449
+ return {};
1450
+ }
1451
+ return JSON.parse(schemaHeader);
1452
+ }
1410
1453
  function validateParams(params) {
1411
1454
  if (!params) return;
1412
1455
  const reservedParams = Object.keys(params).filter(