@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.
@@ -256,15 +256,37 @@ var MessageParser = class {
256
256
  parse(messages, schema) {
257
257
  return JSON.parse(messages, (key, value) => {
258
258
  if ((key === `value` || key === `old_value`) && typeof value === `object` && value !== null) {
259
- const row = value;
260
- Object.keys(row).forEach((key2) => {
261
- row[key2] = this.parseRow(key2, row[key2], schema);
262
- });
263
- if (this.transformer) value = this.transformer(value);
259
+ return this.transformMessageValue(value, schema);
264
260
  }
265
261
  return value;
266
262
  });
267
263
  }
264
+ /**
265
+ * Parse an array of ChangeMessages from a snapshot response.
266
+ * Applies type parsing and transformations to the value and old_value properties.
267
+ */
268
+ parseSnapshotData(messages, schema) {
269
+ return messages.map((message) => {
270
+ const msg = message;
271
+ if (msg.value && typeof msg.value === `object` && msg.value !== null) {
272
+ msg.value = this.transformMessageValue(msg.value, schema);
273
+ }
274
+ if (msg.old_value && typeof msg.old_value === `object` && msg.old_value !== null) {
275
+ msg.old_value = this.transformMessageValue(msg.old_value, schema);
276
+ }
277
+ return msg;
278
+ });
279
+ }
280
+ /**
281
+ * Transform a message value or old_value object by parsing its columns.
282
+ */
283
+ transformMessageValue(value, schema) {
284
+ const row = value;
285
+ Object.keys(row).forEach((key) => {
286
+ row[key] = this.parseRow(key, row[key], schema);
287
+ });
288
+ return this.transformer ? this.transformer(row) : row;
289
+ }
268
290
  // Parses the message values using the provided parser based on the schema information
269
291
  parseRow(key, value, schema) {
270
292
  var _b;
@@ -810,9 +832,8 @@ function canonicalShapeKey(url) {
810
832
  cleanUrl.searchParams.sort();
811
833
  return cleanUrl.toString();
812
834
  }
813
- 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;
835
+ 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;
814
836
  var ShapeStream = class {
815
- // Maximum delay cap (ms)
816
837
  constructor(options) {
817
838
  __privateAdd(this, _ShapeStream_instances);
818
839
  __privateAdd(this, _error, null);
@@ -856,6 +877,8 @@ var ShapeStream = class {
856
877
  __privateAdd(this, _sseBackoffBaseDelay, 100);
857
878
  // Base delay for exponential backoff (ms)
858
879
  __privateAdd(this, _sseBackoffMaxDelay, 5e3);
880
+ // Maximum delay cap (ms)
881
+ __privateAdd(this, _unsubscribeFromVisibilityChanges);
859
882
  var _a, _b, _c, _d;
860
883
  this.options = __spreadValues({ subscribe: true }, options);
861
884
  validateOptions(this.options);
@@ -911,7 +934,9 @@ var ShapeStream = class {
911
934
  };
912
935
  }
913
936
  unsubscribeAll() {
937
+ var _a;
914
938
  __privateGet(this, _subscribers).clear();
939
+ (_a = __privateGet(this, _unsubscribeFromVisibilityChanges)) == null ? void 0 : _a.call(this);
915
940
  }
916
941
  /** Unix time at which we last synced. Undefined when `isLoading` is true. */
917
942
  lastSyncedAt() {
@@ -954,7 +979,7 @@ var ShapeStream = class {
954
979
  });
955
980
  }
956
981
  /**
957
- * Request a snapshot for subset of data.
982
+ * Request a snapshot for subset of data and inject it into the subscribed data stream.
958
983
  *
959
984
  * Only available when mode is `changes_only`.
960
985
  * Returns the insertion point & the data, but more importantly injects the data
@@ -981,8 +1006,7 @@ var ShapeStream = class {
981
1006
  if (__privateGet(this, _activeSnapshotRequests) === 1) {
982
1007
  __privateMethod(this, _ShapeStream_instances, pause_fn).call(this);
983
1008
  }
984
- const { fetchUrl, requestHeaders } = yield __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, this.options.url, true, opts);
985
- const { metadata, data } = yield __privateMethod(this, _ShapeStream_instances, fetchSnapshot_fn).call(this, fetchUrl, requestHeaders);
1009
+ const { metadata, data } = yield this.fetchSnapshot(opts);
986
1010
  const dataWithEndBoundary = data.concat([
987
1011
  { headers: __spreadValues({ control: `snapshot-end` }, metadata) }
988
1012
  ]);
@@ -1003,6 +1027,44 @@ var ShapeStream = class {
1003
1027
  }
1004
1028
  });
1005
1029
  }
1030
+ /**
1031
+ * Fetch a snapshot for subset of data.
1032
+ * Returns the metadata and the data, but does not inject it into the subscribed data stream.
1033
+ *
1034
+ * @param opts - The options for the snapshot request.
1035
+ * @returns The metadata and the data for the snapshot.
1036
+ */
1037
+ fetchSnapshot(opts) {
1038
+ return __async(this, null, function* () {
1039
+ var _a;
1040
+ const { fetchUrl, requestHeaders } = yield __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, this.options.url, true, opts);
1041
+ const response = yield __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
1042
+ headers: requestHeaders
1043
+ });
1044
+ if (!response.ok) {
1045
+ throw new FetchError(
1046
+ response.status,
1047
+ void 0,
1048
+ void 0,
1049
+ Object.fromEntries([...response.headers.entries()]),
1050
+ fetchUrl.toString()
1051
+ );
1052
+ }
1053
+ const schema = (_a = __privateGet(this, _schema)) != null ? _a : getSchemaFromHeaders(response.headers, {
1054
+ required: true,
1055
+ url: fetchUrl.toString()
1056
+ });
1057
+ const { metadata, data: rawData } = yield response.json();
1058
+ const data = __privateGet(this, _messageParser).parseSnapshotData(
1059
+ rawData,
1060
+ schema
1061
+ );
1062
+ return {
1063
+ metadata,
1064
+ data
1065
+ };
1066
+ });
1067
+ }
1006
1068
  };
1007
1069
  _error = new WeakMap();
1008
1070
  _fetchClient2 = new WeakMap();
@@ -1038,6 +1100,7 @@ _maxShortSseConnections = new WeakMap();
1038
1100
  _sseFallbackToLongPolling = new WeakMap();
1039
1101
  _sseBackoffBaseDelay = new WeakMap();
1040
1102
  _sseBackoffMaxDelay = new WeakMap();
1103
+ _unsubscribeFromVisibilityChanges = new WeakMap();
1041
1104
  _ShapeStream_instances = new WeakSet();
1042
1105
  start_fn = function() {
1043
1106
  return __async(this, null, function* () {
@@ -1107,7 +1170,8 @@ requestShape_fn = function() {
1107
1170
  return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
1108
1171
  }
1109
1172
  if (e instanceof FetchBackoffAbortError) {
1110
- if (requestAbortController.signal.aborted && requestAbortController.signal.reason === PAUSE_STREAM) {
1173
+ const currentState = __privateGet(this, _state);
1174
+ if (requestAbortController.signal.aborted && requestAbortController.signal.reason === PAUSE_STREAM && currentState === `pause-requested`) {
1111
1175
  __privateSet(this, _state, `paused`);
1112
1176
  }
1113
1177
  return;
@@ -1175,7 +1239,8 @@ constructUrl_fn = function(url, resumingFromPause, subsetParams) {
1175
1239
  }
1176
1240
  fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
1177
1241
  fetchUrl.searchParams.set(LOG_MODE_QUERY_PARAM, __privateGet(this, _mode));
1178
- if (__privateGet(this, _isUpToDate)) {
1242
+ const isSnapshotRequest = subsetParams !== void 0;
1243
+ if (__privateGet(this, _isUpToDate) && !isSnapshotRequest) {
1179
1244
  if (!__privateGet(this, _isRefreshing) && !resumingFromPause) {
1180
1245
  fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
1181
1246
  }
@@ -1232,11 +1297,7 @@ onInitialResponse_fn = function(response) {
1232
1297
  if (liveCacheBuster) {
1233
1298
  __privateSet(this, _liveCacheBuster, liveCacheBuster);
1234
1299
  }
1235
- const getSchema = () => {
1236
- const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
1237
- return schemaHeader ? JSON.parse(schemaHeader) : {};
1238
- };
1239
- __privateSet(this, _schema, (_a = __privateGet(this, _schema)) != null ? _a : getSchema());
1300
+ __privateSet(this, _schema, (_a = __privateGet(this, _schema)) != null ? _a : getSchemaFromHeaders(headers));
1240
1301
  if (status === 204) {
1241
1302
  __privateSet(this, _lastSyncedAt, Date.now());
1242
1303
  }
@@ -1368,7 +1429,10 @@ pause_fn = function() {
1368
1429
  }
1369
1430
  };
1370
1431
  resume_fn = function() {
1371
- if (__privateGet(this, _started) && __privateGet(this, _state) === `paused`) {
1432
+ if (__privateGet(this, _started) && (__privateGet(this, _state) === `paused` || __privateGet(this, _state) === `pause-requested`)) {
1433
+ if (__privateGet(this, _state) === `pause-requested`) {
1434
+ __privateSet(this, _state, `active`);
1435
+ }
1372
1436
  __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
1373
1437
  }
1374
1438
  };
@@ -1440,6 +1504,9 @@ subscribeToVisibilityChanges_fn = function() {
1440
1504
  }
1441
1505
  };
1442
1506
  document.addEventListener(`visibilitychange`, visibilityHandler);
1507
+ __privateSet(this, _unsubscribeFromVisibilityChanges, () => {
1508
+ document.removeEventListener(`visibilitychange`, visibilityHandler);
1509
+ });
1443
1510
  }
1444
1511
  };
1445
1512
  /**
@@ -1458,33 +1525,20 @@ reset_fn = function(handle) {
1458
1525
  __privateSet(this, _consecutiveShortSseConnections, 0);
1459
1526
  __privateSet(this, _sseFallbackToLongPolling, false);
1460
1527
  };
1461
- fetchSnapshot_fn = function(url, headers) {
1462
- return __async(this, null, function* () {
1463
- const response = yield __privateGet(this, _fetchClient2).call(this, url.toString(), { headers });
1464
- if (!response.ok) {
1465
- throw new FetchError(
1466
- response.status,
1467
- void 0,
1468
- void 0,
1469
- Object.fromEntries([...response.headers.entries()]),
1470
- url.toString()
1471
- );
1472
- }
1473
- const { metadata, data } = yield response.json();
1474
- const batch = __privateGet(this, _messageParser).parse(
1475
- JSON.stringify(data),
1476
- __privateGet(this, _schema)
1477
- );
1478
- return {
1479
- metadata,
1480
- data: batch
1481
- };
1482
- });
1483
- };
1484
1528
  ShapeStream.Replica = {
1485
1529
  FULL: `full`,
1486
1530
  DEFAULT: `default`
1487
1531
  };
1532
+ function getSchemaFromHeaders(headers, options) {
1533
+ const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
1534
+ if (!schemaHeader) {
1535
+ if ((options == null ? void 0 : options.required) && (options == null ? void 0 : options.url)) {
1536
+ throw new MissingHeadersError(options.url, [SHAPE_SCHEMA_HEADER]);
1537
+ }
1538
+ return {};
1539
+ }
1540
+ return JSON.parse(schemaHeader);
1541
+ }
1488
1542
  function validateParams(params) {
1489
1543
  if (!params) return;
1490
1544
  const reservedParams = Object.keys(params).filter(