@electric-sql/client 1.0.12 → 1.0.13
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/cjs/index.cjs +24 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +83 -46
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.ts +83 -46
- package/dist/index.legacy-esm.js +24 -0
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +24 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +48 -1
- package/src/helpers.ts +38 -0
- package/src/index.ts +1 -0
package/src/client.ts
CHANGED
|
@@ -9,7 +9,13 @@ import {
|
|
|
9
9
|
SnapshotMetadata,
|
|
10
10
|
} from './types'
|
|
11
11
|
import { MessageParser, Parser, TransformFunction } from './parser'
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
getOffset,
|
|
14
|
+
isUpToDateMessage,
|
|
15
|
+
isChangeMessage,
|
|
16
|
+
applySubdomainSharding,
|
|
17
|
+
ShardSubdomainOption,
|
|
18
|
+
} from './helpers'
|
|
13
19
|
import {
|
|
14
20
|
FetchError,
|
|
15
21
|
FetchBackoffAbortError,
|
|
@@ -282,6 +288,43 @@ export interface ShapeStreamOptions<T = never> {
|
|
|
282
288
|
*/
|
|
283
289
|
log?: LogMode
|
|
284
290
|
|
|
291
|
+
/**
|
|
292
|
+
* Enable subdomain sharding to bypass browser HTTP/1.1 connection limits.
|
|
293
|
+
* This is useful in local development and is enabled by default for localhost URLs.
|
|
294
|
+
*
|
|
295
|
+
* See https://electric-sql.com/docs/guides/troubleshooting#slow-shapes-mdash-why-are-my-shapes-slow-in-the-browser-in-local-development
|
|
296
|
+
*
|
|
297
|
+
* When sharded, each shape stream gets a unique subdomain (e.g., `a7f2c.localhost`),
|
|
298
|
+
* which bypasses the browser HTTP/1.1 connection limits. This avoids the need to serve
|
|
299
|
+
* the development server over HTTP/2 (and thus HTTPS) in development.
|
|
300
|
+
*
|
|
301
|
+
* Options:
|
|
302
|
+
* - `'localhost'` - Automatically shard `localhost` and `*.localhost` URLs (the default)
|
|
303
|
+
* - `'always'` - Shard URLs regardless of the hostname
|
|
304
|
+
* - `'never'` - Disable sharding
|
|
305
|
+
* - `true` - Alias for `'always'`
|
|
306
|
+
* - `false` - Alias for `'never'`
|
|
307
|
+
*
|
|
308
|
+
* @default 'localhost'
|
|
309
|
+
*
|
|
310
|
+
* @example
|
|
311
|
+
* { url: 'http://localhost:3000/v1/shape', shardSubdomain: 'localhost' }
|
|
312
|
+
* // → http://a1c2f.localhost:3000/v1/shape
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
* { url: 'https://api.example.com', shardSubdomain: 'localhost' }
|
|
316
|
+
* // → https://api.example.com
|
|
317
|
+
*
|
|
318
|
+
* @example
|
|
319
|
+
* { url: 'https://localhost:3000', shardSubdomain: 'never' }
|
|
320
|
+
* // → https://localhost:3000
|
|
321
|
+
*
|
|
322
|
+
* @example
|
|
323
|
+
* { url: 'https://api.example.com', shardSubdomain: 'always' }
|
|
324
|
+
* // → https://b2d3g.api.example.com
|
|
325
|
+
*/
|
|
326
|
+
shardSubdomain?: ShardSubdomainOption
|
|
327
|
+
|
|
285
328
|
signal?: AbortSignal
|
|
286
329
|
fetchClient?: typeof fetch
|
|
287
330
|
backoffOptions?: BackoffOptions
|
|
@@ -439,6 +482,10 @@ export class ShapeStream<T extends Row<unknown> = Row>
|
|
|
439
482
|
constructor(options: ShapeStreamOptions<GetExtensions<T>>) {
|
|
440
483
|
this.options = { subscribe: true, ...options }
|
|
441
484
|
validateOptions(this.options)
|
|
485
|
+
this.options.url = applySubdomainSharding(
|
|
486
|
+
this.options.url,
|
|
487
|
+
this.options.shardSubdomain
|
|
488
|
+
)
|
|
442
489
|
this.#lastOffset = this.options.offset ?? `-1`
|
|
443
490
|
this.#liveCacheBuster = ``
|
|
444
491
|
this.#shapeHandle = this.options.handle
|
package/src/helpers.ts
CHANGED
|
@@ -97,3 +97,41 @@ export function isVisibleInSnapshot(
|
|
|
97
97
|
|
|
98
98
|
return xid < xmin || (xid < xmax && !xip.includes(xid))
|
|
99
99
|
}
|
|
100
|
+
|
|
101
|
+
export function generateShardId(): string {
|
|
102
|
+
return Math.floor(Math.random() * 0xfffff)
|
|
103
|
+
.toString(16)
|
|
104
|
+
.padStart(5, `0`)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function isLocalhostUrl(url: URL): boolean {
|
|
108
|
+
const hostname = url.hostname.toLowerCase()
|
|
109
|
+
return hostname === `localhost` || hostname.endsWith(`.localhost`)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export type ShardSubdomainOption = `always` | `localhost` | `never` | boolean
|
|
113
|
+
|
|
114
|
+
export function applySubdomainSharding(
|
|
115
|
+
originalUrl: string,
|
|
116
|
+
option: ShardSubdomainOption = `localhost`
|
|
117
|
+
): string {
|
|
118
|
+
if (option === `never` || option === false) {
|
|
119
|
+
return originalUrl
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const url = new URL(originalUrl)
|
|
123
|
+
|
|
124
|
+
const shouldShard =
|
|
125
|
+
option === `always` ||
|
|
126
|
+
option === true ||
|
|
127
|
+
(option === `localhost` && isLocalhostUrl(url))
|
|
128
|
+
|
|
129
|
+
if (!shouldShard) {
|
|
130
|
+
return originalUrl
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const shardId = generateShardId()
|
|
134
|
+
url.hostname = `${shardId}.${url.hostname}`
|
|
135
|
+
|
|
136
|
+
return url.toString()
|
|
137
|
+
}
|