@electric-sql/client 1.1.3 → 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.mjs CHANGED
@@ -225,15 +225,37 @@ var MessageParser = class {
225
225
  parse(messages, schema) {
226
226
  return JSON.parse(messages, (key, value) => {
227
227
  if ((key === `value` || key === `old_value`) && typeof value === `object` && value !== null) {
228
- const row = value;
229
- Object.keys(row).forEach((key2) => {
230
- row[key2] = this.parseRow(key2, row[key2], schema);
231
- });
232
- if (this.transformer) value = this.transformer(value);
228
+ return this.transformMessageValue(value, schema);
233
229
  }
234
230
  return value;
235
231
  });
236
232
  }
233
+ /**
234
+ * Parse an array of ChangeMessages from a snapshot response.
235
+ * Applies type parsing and transformations to the value and old_value properties.
236
+ */
237
+ parseSnapshotData(messages, schema) {
238
+ return messages.map((message) => {
239
+ const msg = message;
240
+ if (msg.value && typeof msg.value === `object` && msg.value !== null) {
241
+ msg.value = this.transformMessageValue(msg.value, schema);
242
+ }
243
+ if (msg.old_value && typeof msg.old_value === `object` && msg.old_value !== null) {
244
+ msg.old_value = this.transformMessageValue(msg.old_value, schema);
245
+ }
246
+ return msg;
247
+ });
248
+ }
249
+ /**
250
+ * Transform a message value or old_value object by parsing its columns.
251
+ */
252
+ transformMessageValue(value, schema) {
253
+ const row = value;
254
+ Object.keys(row).forEach((key) => {
255
+ row[key] = this.parseRow(key, row[key], schema);
256
+ });
257
+ return this.transformer ? this.transformer(row) : row;
258
+ }
237
259
  // Parses the message values using the provided parser based on the schema information
238
260
  parseRow(key, value, schema) {
239
261
  var _b;
@@ -781,9 +803,8 @@ function canonicalShapeKey(url) {
781
803
  cleanUrl.searchParams.sort();
782
804
  return cleanUrl.toString();
783
805
  }
784
- 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, _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;
806
+ 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;
785
807
  var ShapeStream = class {
786
- // Maximum delay cap (ms)
787
808
  constructor(options) {
788
809
  __privateAdd(this, _ShapeStream_instances);
789
810
  __privateAdd(this, _error, null);
@@ -827,6 +848,8 @@ var ShapeStream = class {
827
848
  __privateAdd(this, _sseBackoffBaseDelay, 100);
828
849
  // Base delay for exponential backoff (ms)
829
850
  __privateAdd(this, _sseBackoffMaxDelay, 5e3);
851
+ // Maximum delay cap (ms)
852
+ __privateAdd(this, _unsubscribeFromVisibilityChanges);
830
853
  var _a, _b, _c, _d;
831
854
  this.options = __spreadValues({ subscribe: true }, options);
832
855
  validateOptions(this.options);
@@ -882,7 +905,9 @@ var ShapeStream = class {
882
905
  };
883
906
  }
884
907
  unsubscribeAll() {
908
+ var _a;
885
909
  __privateGet(this, _subscribers).clear();
910
+ (_a = __privateGet(this, _unsubscribeFromVisibilityChanges)) == null ? void 0 : _a.call(this);
886
911
  }
887
912
  /** Unix time at which we last synced. Undefined when `isLoading` is true. */
888
913
  lastSyncedAt() {
@@ -925,7 +950,7 @@ var ShapeStream = class {
925
950
  });
926
951
  }
927
952
  /**
928
- * Request a snapshot for subset of data.
953
+ * Request a snapshot for subset of data and inject it into the subscribed data stream.
929
954
  *
930
955
  * Only available when mode is `changes_only`.
931
956
  * Returns the insertion point & the data, but more importantly injects the data
@@ -952,8 +977,7 @@ var ShapeStream = class {
952
977
  if (__privateGet(this, _activeSnapshotRequests) === 1) {
953
978
  __privateMethod(this, _ShapeStream_instances, pause_fn).call(this);
954
979
  }
955
- const { fetchUrl, requestHeaders } = yield __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, this.options.url, true, opts);
956
- const { metadata, data } = yield __privateMethod(this, _ShapeStream_instances, fetchSnapshot_fn).call(this, fetchUrl, requestHeaders);
980
+ const { metadata, data } = yield this.fetchSnapshot(opts);
957
981
  const dataWithEndBoundary = data.concat([
958
982
  { headers: __spreadValues({ control: `snapshot-end` }, metadata) }
959
983
  ]);
@@ -974,6 +998,44 @@ var ShapeStream = class {
974
998
  }
975
999
  });
976
1000
  }
1001
+ /**
1002
+ * Fetch a snapshot for subset of data.
1003
+ * Returns the metadata and the data, but does not inject it into the subscribed data stream.
1004
+ *
1005
+ * @param opts - The options for the snapshot request.
1006
+ * @returns The metadata and the data for the snapshot.
1007
+ */
1008
+ fetchSnapshot(opts) {
1009
+ return __async(this, null, function* () {
1010
+ var _a;
1011
+ const { fetchUrl, requestHeaders } = yield __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, this.options.url, true, opts);
1012
+ const response = yield __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
1013
+ headers: requestHeaders
1014
+ });
1015
+ if (!response.ok) {
1016
+ throw new FetchError(
1017
+ response.status,
1018
+ void 0,
1019
+ void 0,
1020
+ Object.fromEntries([...response.headers.entries()]),
1021
+ fetchUrl.toString()
1022
+ );
1023
+ }
1024
+ const schema = (_a = __privateGet(this, _schema)) != null ? _a : getSchemaFromHeaders(response.headers, {
1025
+ required: true,
1026
+ url: fetchUrl.toString()
1027
+ });
1028
+ const { metadata, data: rawData } = yield response.json();
1029
+ const data = __privateGet(this, _messageParser).parseSnapshotData(
1030
+ rawData,
1031
+ schema
1032
+ );
1033
+ return {
1034
+ metadata,
1035
+ data
1036
+ };
1037
+ });
1038
+ }
977
1039
  };
978
1040
  _error = new WeakMap();
979
1041
  _fetchClient2 = new WeakMap();
@@ -1009,6 +1071,7 @@ _maxShortSseConnections = new WeakMap();
1009
1071
  _sseFallbackToLongPolling = new WeakMap();
1010
1072
  _sseBackoffBaseDelay = new WeakMap();
1011
1073
  _sseBackoffMaxDelay = new WeakMap();
1074
+ _unsubscribeFromVisibilityChanges = new WeakMap();
1012
1075
  _ShapeStream_instances = new WeakSet();
1013
1076
  start_fn = function() {
1014
1077
  return __async(this, null, function* () {
@@ -1078,7 +1141,8 @@ requestShape_fn = function() {
1078
1141
  return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
1079
1142
  }
1080
1143
  if (e instanceof FetchBackoffAbortError) {
1081
- if (requestAbortController.signal.aborted && requestAbortController.signal.reason === PAUSE_STREAM) {
1144
+ const currentState = __privateGet(this, _state);
1145
+ if (requestAbortController.signal.aborted && requestAbortController.signal.reason === PAUSE_STREAM && currentState === `pause-requested`) {
1082
1146
  __privateSet(this, _state, `paused`);
1083
1147
  }
1084
1148
  return;
@@ -1146,7 +1210,8 @@ constructUrl_fn = function(url, resumingFromPause, subsetParams) {
1146
1210
  }
1147
1211
  fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
1148
1212
  fetchUrl.searchParams.set(LOG_MODE_QUERY_PARAM, __privateGet(this, _mode));
1149
- if (__privateGet(this, _isUpToDate)) {
1213
+ const isSnapshotRequest = subsetParams !== void 0;
1214
+ if (__privateGet(this, _isUpToDate) && !isSnapshotRequest) {
1150
1215
  if (!__privateGet(this, _isRefreshing) && !resumingFromPause) {
1151
1216
  fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
1152
1217
  }
@@ -1203,11 +1268,7 @@ onInitialResponse_fn = function(response) {
1203
1268
  if (liveCacheBuster) {
1204
1269
  __privateSet(this, _liveCacheBuster, liveCacheBuster);
1205
1270
  }
1206
- const getSchema = () => {
1207
- const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
1208
- return schemaHeader ? JSON.parse(schemaHeader) : {};
1209
- };
1210
- __privateSet(this, _schema, (_a = __privateGet(this, _schema)) != null ? _a : getSchema());
1271
+ __privateSet(this, _schema, (_a = __privateGet(this, _schema)) != null ? _a : getSchemaFromHeaders(headers));
1211
1272
  if (status === 204) {
1212
1273
  __privateSet(this, _lastSyncedAt, Date.now());
1213
1274
  }
@@ -1339,7 +1400,10 @@ pause_fn = function() {
1339
1400
  }
1340
1401
  };
1341
1402
  resume_fn = function() {
1342
- if (__privateGet(this, _started) && __privateGet(this, _state) === `paused`) {
1403
+ if (__privateGet(this, _started) && (__privateGet(this, _state) === `paused` || __privateGet(this, _state) === `pause-requested`)) {
1404
+ if (__privateGet(this, _state) === `pause-requested`) {
1405
+ __privateSet(this, _state, `active`);
1406
+ }
1343
1407
  __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
1344
1408
  }
1345
1409
  };
@@ -1411,6 +1475,9 @@ subscribeToVisibilityChanges_fn = function() {
1411
1475
  }
1412
1476
  };
1413
1477
  document.addEventListener(`visibilitychange`, visibilityHandler);
1478
+ __privateSet(this, _unsubscribeFromVisibilityChanges, () => {
1479
+ document.removeEventListener(`visibilitychange`, visibilityHandler);
1480
+ });
1414
1481
  }
1415
1482
  };
1416
1483
  /**
@@ -1429,33 +1496,20 @@ reset_fn = function(handle) {
1429
1496
  __privateSet(this, _consecutiveShortSseConnections, 0);
1430
1497
  __privateSet(this, _sseFallbackToLongPolling, false);
1431
1498
  };
1432
- fetchSnapshot_fn = function(url, headers) {
1433
- return __async(this, null, function* () {
1434
- const response = yield __privateGet(this, _fetchClient2).call(this, url.toString(), { headers });
1435
- if (!response.ok) {
1436
- throw new FetchError(
1437
- response.status,
1438
- void 0,
1439
- void 0,
1440
- Object.fromEntries([...response.headers.entries()]),
1441
- url.toString()
1442
- );
1443
- }
1444
- const { metadata, data } = yield response.json();
1445
- const batch = __privateGet(this, _messageParser).parse(
1446
- JSON.stringify(data),
1447
- __privateGet(this, _schema)
1448
- );
1449
- return {
1450
- metadata,
1451
- data: batch
1452
- };
1453
- });
1454
- };
1455
1499
  ShapeStream.Replica = {
1456
1500
  FULL: `full`,
1457
1501
  DEFAULT: `default`
1458
1502
  };
1503
+ function getSchemaFromHeaders(headers, options) {
1504
+ const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
1505
+ if (!schemaHeader) {
1506
+ if ((options == null ? void 0 : options.required) && (options == null ? void 0 : options.url)) {
1507
+ throw new MissingHeadersError(options.url, [SHAPE_SCHEMA_HEADER]);
1508
+ }
1509
+ return {};
1510
+ }
1511
+ return JSON.parse(schemaHeader);
1512
+ }
1459
1513
  function validateParams(params) {
1460
1514
  if (!params) return;
1461
1515
  const reservedParams = Object.keys(params).filter(