@electric-sql/client 1.0.13 → 1.1.0

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
@@ -118,52 +118,6 @@ type Parser<Extensions = never> = {
118
118
  };
119
119
  type TransformFunction<Extensions = never> = (message: Row<Extensions>) => Row<Extensions>;
120
120
 
121
- /**
122
- * Type guard for checking {@link Message} is {@link ChangeMessage}.
123
- *
124
- * See [TS docs](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards)
125
- * for information on how to use type guards.
126
- *
127
- * @param message - the message to check
128
- * @returns true if the message is a {@link ChangeMessage}
129
- *
130
- * @example
131
- * ```ts
132
- * if (isChangeMessage(message)) {
133
- * const msgChng: ChangeMessage = message // Ok
134
- * const msgCtrl: ControlMessage = message // Err, type mismatch
135
- * }
136
- * ```
137
- */
138
- declare function isChangeMessage<T extends Row<unknown> = Row>(message: Message<T>): message is ChangeMessage<T>;
139
- /**
140
- * Type guard for checking {@link Message} is {@link ControlMessage}.
141
- *
142
- * See [TS docs](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards)
143
- * for information on how to use type guards.
144
- *
145
- * @param message - the message to check
146
- * @returns true if the message is a {@link ControlMessage}
147
- *
148
- * * @example
149
- * ```ts
150
- * if (isControlMessage(message)) {
151
- * const msgChng: ChangeMessage = message // Err, type mismatch
152
- * const msgCtrl: ControlMessage = message // Ok
153
- * }
154
- * ```
155
- */
156
- declare function isControlMessage<T extends Row<unknown> = Row>(message: Message<T>): message is ControlMessage;
157
- /**
158
- * Checks if a transaction is visible in a snapshot.
159
- *
160
- * @param txid - the transaction id to check
161
- * @param snapshot - the information about the snapshot
162
- * @returns true if the transaction is visible in the snapshot
163
- */
164
- declare function isVisibleInSnapshot(txid: number | bigint | `${bigint}`, snapshot: PostgresSnapshot | NormalizedPgSnapshot): boolean;
165
- type ShardSubdomainOption = `always` | `localhost` | `never` | boolean;
166
-
167
121
  declare class FetchError extends Error {
168
122
  url: string;
169
123
  status: number;
@@ -324,49 +278,17 @@ interface ShapeStreamOptions<T = never> {
324
278
  */
325
279
  subscribe?: boolean;
326
280
  /**
327
- * Experimental support for Server-Sent Events (SSE) for live updates.
281
+ * @deprecated No longer experimental, use {@link liveSse} instead.
328
282
  */
329
283
  experimentalLiveSse?: boolean;
330
284
  /**
331
- * Initial data loading mode
285
+ * Use Server-Sent Events (SSE) for live updates.
332
286
  */
333
- log?: LogMode;
287
+ liveSse?: boolean;
334
288
  /**
335
- * Enable subdomain sharding to bypass browser HTTP/1.1 connection limits.
336
- * This is useful in local development and is enabled by default for localhost URLs.
337
- *
338
- * See https://electric-sql.com/docs/guides/troubleshooting#slow-shapes-mdash-why-are-my-shapes-slow-in-the-browser-in-local-development
339
- *
340
- * When sharded, each shape stream gets a unique subdomain (e.g., `a7f2c.localhost`),
341
- * which bypasses the browser HTTP/1.1 connection limits. This avoids the need to serve
342
- * the development server over HTTP/2 (and thus HTTPS) in development.
343
- *
344
- * Options:
345
- * - `'localhost'` - Automatically shard `localhost` and `*.localhost` URLs (the default)
346
- * - `'always'` - Shard URLs regardless of the hostname
347
- * - `'never'` - Disable sharding
348
- * - `true` - Alias for `'always'`
349
- * - `false` - Alias for `'never'`
350
- *
351
- * @default 'localhost'
352
- *
353
- * @example
354
- * { url: 'http://localhost:3000/v1/shape', shardSubdomain: 'localhost' }
355
- * // → http://a1c2f.localhost:3000/v1/shape
356
- *
357
- * @example
358
- * { url: 'https://api.example.com', shardSubdomain: 'localhost' }
359
- * // → https://api.example.com
360
- *
361
- * @example
362
- * { url: 'https://localhost:3000', shardSubdomain: 'never' }
363
- * // → https://localhost:3000
364
- *
365
- * @example
366
- * { url: 'https://api.example.com', shardSubdomain: 'always' }
367
- * // → https://b2d3g.api.example.com
289
+ * Initial data loading mode
368
290
  */
369
- shardSubdomain?: ShardSubdomainOption;
291
+ log?: LogMode;
370
292
  signal?: AbortSignal;
371
293
  fetchClient?: typeof fetch;
372
294
  backoffOptions?: BackoffOptions;
@@ -430,7 +352,7 @@ interface ShapeStreamInterface<T extends Row<unknown> = Row> {
430
352
  * ```
431
353
  * const stream = new ShapeStream({
432
354
  * url: `http://localhost:3000/v1/shape`,
433
- * experimentalLiveSse: true
355
+ * liveSse: true
434
356
  * })
435
357
  * ```
436
358
  *
@@ -572,4 +494,49 @@ declare class Shape<T extends Row<unknown> = Row> {
572
494
  get numSubscribers(): number;
573
495
  }
574
496
 
575
- export { BackoffDefaults, type BackoffOptions, type BitColumn, type BpcharColumn, type ChangeMessage, type ColumnInfo, type CommonColumnProps, type ControlMessage, ELECTRIC_PROTOCOL_QUERY_PARAMS, type ExternalHeadersRecord, type ExternalParamsRecord, FetchError, type GetExtensions, type IntervalColumn, type IntervalColumnWithPrecision, type LogMode, type MaybePromise, type Message, type NormalizedPgSnapshot, type NumericColumn, type Offset, type Operation, type PostgresParams, type PostgresSnapshot, type RegularColumn, type Row, type Schema, Shape, type ShapeChangedCallback, type ShapeData, ShapeStream, type ShapeStreamInterface, type ShapeStreamOptions, type ShardSubdomainOption, type SnapshotMetadata, type SubsetParams, type TimeColumn, type TypedMessages, type Value, type VarcharColumn, isChangeMessage, isControlMessage, isVisibleInSnapshot, resolveValue };
497
+ /**
498
+ * Type guard for checking {@link Message} is {@link ChangeMessage}.
499
+ *
500
+ * See [TS docs](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards)
501
+ * for information on how to use type guards.
502
+ *
503
+ * @param message - the message to check
504
+ * @returns true if the message is a {@link ChangeMessage}
505
+ *
506
+ * @example
507
+ * ```ts
508
+ * if (isChangeMessage(message)) {
509
+ * const msgChng: ChangeMessage = message // Ok
510
+ * const msgCtrl: ControlMessage = message // Err, type mismatch
511
+ * }
512
+ * ```
513
+ */
514
+ declare function isChangeMessage<T extends Row<unknown> = Row>(message: Message<T>): message is ChangeMessage<T>;
515
+ /**
516
+ * Type guard for checking {@link Message} is {@link ControlMessage}.
517
+ *
518
+ * See [TS docs](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards)
519
+ * for information on how to use type guards.
520
+ *
521
+ * @param message - the message to check
522
+ * @returns true if the message is a {@link ControlMessage}
523
+ *
524
+ * * @example
525
+ * ```ts
526
+ * if (isControlMessage(message)) {
527
+ * const msgChng: ChangeMessage = message // Err, type mismatch
528
+ * const msgCtrl: ControlMessage = message // Ok
529
+ * }
530
+ * ```
531
+ */
532
+ declare function isControlMessage<T extends Row<unknown> = Row>(message: Message<T>): message is ControlMessage;
533
+ /**
534
+ * Checks if a transaction is visible in a snapshot.
535
+ *
536
+ * @param txid - the transaction id to check
537
+ * @param snapshot - the information about the snapshot
538
+ * @returns true if the transaction is visible in the snapshot
539
+ */
540
+ declare function isVisibleInSnapshot(txid: number | bigint | `${bigint}`, snapshot: PostgresSnapshot | NormalizedPgSnapshot): boolean;
541
+
542
+ export { BackoffDefaults, type BackoffOptions, type BitColumn, type BpcharColumn, type ChangeMessage, type ColumnInfo, type CommonColumnProps, type ControlMessage, ELECTRIC_PROTOCOL_QUERY_PARAMS, type ExternalHeadersRecord, type ExternalParamsRecord, FetchError, type GetExtensions, type IntervalColumn, type IntervalColumnWithPrecision, type LogMode, type MaybePromise, type Message, type NormalizedPgSnapshot, type NumericColumn, type Offset, type Operation, type PostgresParams, type PostgresSnapshot, type RegularColumn, type Row, type Schema, Shape, type ShapeChangedCallback, type ShapeData, ShapeStream, type ShapeStreamInterface, type ShapeStreamOptions, type SnapshotMetadata, type SubsetParams, type TimeColumn, type TypedMessages, type Value, type VarcharColumn, isChangeMessage, isControlMessage, isVisibleInSnapshot, resolveValue };
@@ -271,26 +271,6 @@ function isVisibleInSnapshot(txid, snapshot) {
271
271
  const xip = snapshot.xip_list.map(BigInt);
272
272
  return xid < xmin || xid < xmax && !xip.includes(xid);
273
273
  }
274
- function generateShardId() {
275
- return Math.floor(Math.random() * 1048575).toString(16).padStart(5, `0`);
276
- }
277
- function isLocalhostUrl(url) {
278
- const hostname = url.hostname.toLowerCase();
279
- return hostname === `localhost` || hostname.endsWith(`.localhost`);
280
- }
281
- function applySubdomainSharding(originalUrl, option = `localhost`) {
282
- if (option === `never` || option === false) {
283
- return originalUrl;
284
- }
285
- const url = new URL(originalUrl);
286
- const shouldShard = option === `always` || option === true || option === `localhost` && isLocalhostUrl(url);
287
- if (!shouldShard) {
288
- return originalUrl;
289
- }
290
- const shardId = generateShardId();
291
- url.hostname = `${shardId}.${url.hostname}`;
292
- return url.toString();
293
- }
294
274
 
295
275
  // src/constants.ts
296
276
  var LIVE_CACHE_BUSTER_HEADER = `electric-cursor`;
@@ -309,6 +289,7 @@ var WHERE_QUERY_PARAM = `where`;
309
289
  var REPLICA_PARAM = `replica`;
310
290
  var WHERE_PARAMS_PARAM = `params`;
311
291
  var EXPERIMENTAL_LIVE_SSE_QUERY_PARAM = `experimental_live_sse`;
292
+ var LIVE_SSE_QUERY_PARAM = `live_sse`;
312
293
  var FORCE_DISCONNECT_AND_REFRESH = `force-disconnect-and-refresh`;
313
294
  var PAUSE_STREAM = `pause-stream`;
314
295
  var LOG_MODE_QUERY_PARAM = `log`;
@@ -379,6 +360,7 @@ function createFetchWithBackoff(fetchClient, backoffOptions = BackoffDefaults) {
379
360
  var NO_BODY_STATUS_CODES = [201, 204, 205];
380
361
  function createFetchWithConsumedMessages(fetchClient) {
381
362
  return async (...args) => {
363
+ var _a, _b;
382
364
  const url = args[0];
383
365
  const res = await fetchClient(...args);
384
366
  try {
@@ -388,6 +370,9 @@ function createFetchWithConsumedMessages(fetchClient) {
388
370
  const text = await res.text();
389
371
  return new Response(text, res);
390
372
  } catch (err) {
373
+ if ((_b = (_a = args[1]) == null ? void 0 : _a.signal) == null ? void 0 : _b.aborted) {
374
+ throw new FetchBackoffAbortError();
375
+ }
391
376
  throw new FetchError(
392
377
  res.status,
393
378
  void 0,
@@ -769,10 +754,6 @@ var ShapeStream = class {
769
754
  var _a, _b, _c, _d;
770
755
  this.options = __spreadValues({ subscribe: true }, options);
771
756
  validateOptions(this.options);
772
- this.options.url = applySubdomainSharding(
773
- this.options.url,
774
- this.options.shardSubdomain
775
- );
776
757
  __privateSet(this, _lastOffset, (_a = this.options.offset) != null ? _a : `-1`);
777
758
  __privateSet(this, _liveCacheBuster, ``);
778
759
  __privateSet(this, _shapeHandle, this.options.handle);
@@ -1010,7 +991,7 @@ requestShape_fn = async function() {
1010
991
  }
1011
992
  const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER] || `${__privateGet(this, _shapeHandle)}-next`;
1012
993
  __privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
1013
- await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
994
+ await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, Array.isArray(e.json) ? e.json : [e.json]);
1014
995
  return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
1015
996
  } else {
1016
997
  __privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
@@ -1153,8 +1134,11 @@ onMessages_fn = async function(batch, isSseMessage = false) {
1153
1134
  }
1154
1135
  };
1155
1136
  fetchShape_fn = async function(opts) {
1156
- if (__privateGet(this, _isUpToDate) && this.options.experimentalLiveSse && !__privateGet(this, _isRefreshing) && !opts.resumingFromPause) {
1137
+ var _a;
1138
+ const useSse = (_a = this.options.liveSse) != null ? _a : this.options.experimentalLiveSse;
1139
+ if (__privateGet(this, _isUpToDate) && useSse && !__privateGet(this, _isRefreshing) && !opts.resumingFromPause) {
1157
1140
  opts.fetchUrl.searchParams.set(EXPERIMENTAL_LIVE_SSE_QUERY_PARAM, `true`);
1141
+ opts.fetchUrl.searchParams.set(LIVE_SSE_QUERY_PARAM, `true`);
1158
1142
  return __privateMethod(this, _ShapeStream_instances, requestShapeSSE_fn).call(this, opts);
1159
1143
  }
1160
1144
  return __privateMethod(this, _ShapeStream_instances, requestShapeLongPoll_fn).call(this, opts);