@electric-sql/client 0.7.3 → 0.8.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/README.md +76 -1
- package/dist/cjs/index.cjs +230 -215
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.browser.mjs +5 -4
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.ts +19 -9
- package/dist/index.legacy-esm.js +226 -211
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +230 -215
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +71 -76
- package/src/error.ts +55 -0
- package/src/fetch.ts +1 -1
- package/src/parser.ts +2 -1
- package/src/shape.ts +4 -9
package/dist/index.legacy-esm.js
CHANGED
|
@@ -38,6 +38,89 @@ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot
|
|
|
38
38
|
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
39
39
|
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
40
40
|
|
|
41
|
+
// src/error.ts
|
|
42
|
+
var FetchError = class _FetchError extends Error {
|
|
43
|
+
constructor(status, text, json, headers, url, message) {
|
|
44
|
+
super(
|
|
45
|
+
message || `HTTP Error ${status} at ${url}: ${text != null ? text : JSON.stringify(json)}`
|
|
46
|
+
);
|
|
47
|
+
this.url = url;
|
|
48
|
+
this.name = `FetchError`;
|
|
49
|
+
this.status = status;
|
|
50
|
+
this.text = text;
|
|
51
|
+
this.json = json;
|
|
52
|
+
this.headers = headers;
|
|
53
|
+
}
|
|
54
|
+
static async fromResponse(response, url) {
|
|
55
|
+
const status = response.status;
|
|
56
|
+
const headers = Object.fromEntries([...response.headers.entries()]);
|
|
57
|
+
let text = void 0;
|
|
58
|
+
let json = void 0;
|
|
59
|
+
const contentType = response.headers.get(`content-type`);
|
|
60
|
+
if (contentType && contentType.includes(`application/json`)) {
|
|
61
|
+
json = await response.json();
|
|
62
|
+
} else {
|
|
63
|
+
text = await response.text();
|
|
64
|
+
}
|
|
65
|
+
return new _FetchError(status, text, json, headers, url);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
var FetchBackoffAbortError = class extends Error {
|
|
69
|
+
constructor() {
|
|
70
|
+
super(`Fetch with backoff aborted`);
|
|
71
|
+
this.name = `FetchBackoffAbortError`;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
var MissingShapeUrlError = class extends Error {
|
|
75
|
+
constructor() {
|
|
76
|
+
super(`Invalid shape options: missing required url parameter`);
|
|
77
|
+
this.name = `MissingShapeUrlError`;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
var InvalidSignalError = class extends Error {
|
|
81
|
+
constructor() {
|
|
82
|
+
super(`Invalid signal option. It must be an instance of AbortSignal.`);
|
|
83
|
+
this.name = `InvalidSignalError`;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
var MissingShapeHandleError = class extends Error {
|
|
87
|
+
constructor() {
|
|
88
|
+
super(
|
|
89
|
+
`shapeHandle is required if this isn't an initial fetch (i.e. offset > -1)`
|
|
90
|
+
);
|
|
91
|
+
this.name = `MissingShapeHandleError`;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
var ReservedParamError = class extends Error {
|
|
95
|
+
constructor(reservedParams) {
|
|
96
|
+
super(
|
|
97
|
+
`Cannot use reserved Electric parameter names in custom params: ${reservedParams.join(`, `)}`
|
|
98
|
+
);
|
|
99
|
+
this.name = `ReservedParamError`;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
var ParserNullValueError = class extends Error {
|
|
103
|
+
constructor(columnName) {
|
|
104
|
+
super(`Column "${columnName != null ? columnName : `unknown`}" does not allow NULL values`);
|
|
105
|
+
this.name = `ParserNullValueError`;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
var MissingHeadersError = class extends Error {
|
|
109
|
+
constructor(url, missingHeaders) {
|
|
110
|
+
let msg = `The response for the shape request to ${url} didn't include the following required headers:
|
|
111
|
+
`;
|
|
112
|
+
missingHeaders.forEach((h) => {
|
|
113
|
+
msg += `- ${h}
|
|
114
|
+
`;
|
|
115
|
+
});
|
|
116
|
+
msg += `
|
|
117
|
+
This is often due to a proxy not setting CORS correctly so that all Electric headers can be read by the client.`;
|
|
118
|
+
msg += `
|
|
119
|
+
For more information visit the troubleshooting guide: /docs/guides/troubleshooting/missing-headers`;
|
|
120
|
+
super(msg);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
41
124
|
// src/parser.ts
|
|
42
125
|
var parseNumber = (value) => Number(value);
|
|
43
126
|
var parseBool = (value) => value === `true` || value === `t`;
|
|
@@ -139,7 +222,7 @@ function makeNullableParser(parser, columnInfo, columnName) {
|
|
|
139
222
|
return (value) => {
|
|
140
223
|
if (isPgNull(value)) {
|
|
141
224
|
if (!isNullable) {
|
|
142
|
-
throw new
|
|
225
|
+
throw new ParserNullValueError(columnName != null ? columnName : `unknown`);
|
|
143
226
|
}
|
|
144
227
|
return null;
|
|
145
228
|
}
|
|
@@ -161,52 +244,6 @@ function isUpToDateMessage(message) {
|
|
|
161
244
|
return isControlMessage(message) && message.headers.control === `up-to-date`;
|
|
162
245
|
}
|
|
163
246
|
|
|
164
|
-
// src/error.ts
|
|
165
|
-
var FetchError = class _FetchError extends Error {
|
|
166
|
-
constructor(status, text, json, headers, url, message) {
|
|
167
|
-
super(
|
|
168
|
-
message || `HTTP Error ${status} at ${url}: ${text != null ? text : JSON.stringify(json)}`
|
|
169
|
-
);
|
|
170
|
-
this.url = url;
|
|
171
|
-
this.name = `FetchError`;
|
|
172
|
-
this.status = status;
|
|
173
|
-
this.text = text;
|
|
174
|
-
this.json = json;
|
|
175
|
-
this.headers = headers;
|
|
176
|
-
}
|
|
177
|
-
static async fromResponse(response, url) {
|
|
178
|
-
const status = response.status;
|
|
179
|
-
const headers = Object.fromEntries([...response.headers.entries()]);
|
|
180
|
-
let text = void 0;
|
|
181
|
-
let json = void 0;
|
|
182
|
-
const contentType = response.headers.get(`content-type`);
|
|
183
|
-
if (contentType && contentType.includes(`application/json`)) {
|
|
184
|
-
json = await response.json();
|
|
185
|
-
} else {
|
|
186
|
-
text = await response.text();
|
|
187
|
-
}
|
|
188
|
-
return new _FetchError(status, text, json, headers, url);
|
|
189
|
-
}
|
|
190
|
-
};
|
|
191
|
-
var FetchBackoffAbortError = class extends Error {
|
|
192
|
-
constructor() {
|
|
193
|
-
super(`Fetch with backoff aborted`);
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
var MissingHeadersError = class extends Error {
|
|
197
|
-
constructor(url, missingHeaders) {
|
|
198
|
-
let msg = `The response for the shape request to ${url} didn't include the following required headers:
|
|
199
|
-
`;
|
|
200
|
-
missingHeaders.forEach((h) => {
|
|
201
|
-
msg += `- ${h}
|
|
202
|
-
`;
|
|
203
|
-
});
|
|
204
|
-
msg += `
|
|
205
|
-
This is often due to a proxy not setting CORS correctly so that all Electric headers can be read by the client.`;
|
|
206
|
-
super(msg);
|
|
207
|
-
}
|
|
208
|
-
};
|
|
209
|
-
|
|
210
247
|
// src/constants.ts
|
|
211
248
|
var LIVE_CACHE_BUSTER_HEADER = `electric-cursor`;
|
|
212
249
|
var SHAPE_HANDLE_HEADER = `electric-handle`;
|
|
@@ -306,7 +343,7 @@ function createFetchWithResponseHeadersCheck(fetchClient) {
|
|
|
306
343
|
if (response.ok) {
|
|
307
344
|
const headers = response.headers;
|
|
308
345
|
const missingHeaders = [];
|
|
309
|
-
const addMissingHeaders = (requiredHeaders) => requiredHeaders.filter((h) => !headers.has(h));
|
|
346
|
+
const addMissingHeaders = (requiredHeaders) => missingHeaders.push(...requiredHeaders.filter((h) => !headers.has(h)));
|
|
310
347
|
addMissingHeaders(requiredElectricResponseHeaders);
|
|
311
348
|
const input = args[0];
|
|
312
349
|
const urlString = input.toString();
|
|
@@ -423,14 +460,14 @@ var RESERVED_PARAMS = /* @__PURE__ */ new Set([
|
|
|
423
460
|
WHERE_QUERY_PARAM,
|
|
424
461
|
REPLICA_PARAM
|
|
425
462
|
]);
|
|
426
|
-
var _fetchClient2, _messageParser, _subscribers,
|
|
463
|
+
var _error, _fetchClient2, _messageParser, _subscribers, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _connected, _shapeHandle, _databaseId, _schema, _onError, _replica, _ShapeStream_instances, start_fn, publish_fn, sendErrorToSubscribers_fn, reset_fn;
|
|
427
464
|
var _ShapeStream = class _ShapeStream {
|
|
428
465
|
constructor(options) {
|
|
429
466
|
__privateAdd(this, _ShapeStream_instances);
|
|
467
|
+
__privateAdd(this, _error, null);
|
|
430
468
|
__privateAdd(this, _fetchClient2);
|
|
431
469
|
__privateAdd(this, _messageParser);
|
|
432
470
|
__privateAdd(this, _subscribers, /* @__PURE__ */ new Map());
|
|
433
|
-
__privateAdd(this, _upToDateSubscribers, /* @__PURE__ */ new Map());
|
|
434
471
|
__privateAdd(this, _lastOffset);
|
|
435
472
|
__privateAdd(this, _liveCacheBuster);
|
|
436
473
|
// Seconds since our Electric Epoch 😎
|
|
@@ -441,17 +478,18 @@ var _ShapeStream = class _ShapeStream {
|
|
|
441
478
|
__privateAdd(this, _shapeHandle);
|
|
442
479
|
__privateAdd(this, _databaseId);
|
|
443
480
|
__privateAdd(this, _schema);
|
|
444
|
-
__privateAdd(this,
|
|
481
|
+
__privateAdd(this, _onError);
|
|
445
482
|
__privateAdd(this, _replica);
|
|
446
483
|
var _a, _b, _c;
|
|
447
|
-
validateOptions(options);
|
|
448
484
|
this.options = __spreadValues({ subscribe: true }, options);
|
|
485
|
+
validateOptions(this.options);
|
|
449
486
|
__privateSet(this, _lastOffset, (_a = this.options.offset) != null ? _a : `-1`);
|
|
450
487
|
__privateSet(this, _liveCacheBuster, ``);
|
|
451
|
-
__privateSet(this, _shapeHandle, this.options.
|
|
488
|
+
__privateSet(this, _shapeHandle, this.options.handle);
|
|
452
489
|
__privateSet(this, _databaseId, this.options.databaseId);
|
|
453
490
|
__privateSet(this, _messageParser, new MessageParser(options.parser));
|
|
454
491
|
__privateSet(this, _replica, this.options.replica);
|
|
492
|
+
__privateSet(this, _onError, this.options.onError);
|
|
455
493
|
const baseFetchClient = (_b = options.fetchClient) != null ? _b : (...args) => fetch(...args);
|
|
456
494
|
const fetchWithBackoffClient = createFetchWithBackoff(baseFetchClient, __spreadProps(__spreadValues({}, (_c = options.backoffOptions) != null ? _c : BackoffDefaults), {
|
|
457
495
|
onFailedAttempt: () => {
|
|
@@ -463,129 +501,22 @@ var _ShapeStream = class _ShapeStream {
|
|
|
463
501
|
__privateSet(this, _fetchClient2, createFetchWithResponseHeadersCheck(
|
|
464
502
|
createFetchWithChunkBuffer(fetchWithBackoffClient)
|
|
465
503
|
));
|
|
466
|
-
this.
|
|
504
|
+
__privateMethod(this, _ShapeStream_instances, start_fn).call(this);
|
|
467
505
|
}
|
|
468
506
|
get shapeHandle() {
|
|
469
507
|
return __privateGet(this, _shapeHandle);
|
|
470
508
|
}
|
|
509
|
+
get error() {
|
|
510
|
+
return __privateGet(this, _error);
|
|
511
|
+
}
|
|
471
512
|
get isUpToDate() {
|
|
472
513
|
return __privateGet(this, _isUpToDate);
|
|
473
514
|
}
|
|
474
515
|
get lastOffset() {
|
|
475
516
|
return __privateGet(this, _lastOffset);
|
|
476
517
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
}
|
|
480
|
-
async start() {
|
|
481
|
-
var _a, _b;
|
|
482
|
-
__privateSet(this, _isUpToDate, false);
|
|
483
|
-
const { url, table, where, columns, signal } = this.options;
|
|
484
|
-
try {
|
|
485
|
-
while (!(signal == null ? void 0 : signal.aborted) && !__privateGet(this, _isUpToDate) || this.options.subscribe) {
|
|
486
|
-
const fetchUrl = new URL(url);
|
|
487
|
-
if (this.options.params) {
|
|
488
|
-
const reservedParams = Object.keys(this.options.params).filter(
|
|
489
|
-
(key) => RESERVED_PARAMS.has(key)
|
|
490
|
-
);
|
|
491
|
-
if (reservedParams.length > 0) {
|
|
492
|
-
throw new Error(
|
|
493
|
-
`Cannot use reserved Electric parameter names in custom params: ${reservedParams.join(`, `)}`
|
|
494
|
-
);
|
|
495
|
-
}
|
|
496
|
-
for (const [key, value] of Object.entries(this.options.params)) {
|
|
497
|
-
fetchUrl.searchParams.set(key, value);
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
if (table) fetchUrl.searchParams.set(TABLE_QUERY_PARAM, table);
|
|
501
|
-
if (where) fetchUrl.searchParams.set(WHERE_QUERY_PARAM, where);
|
|
502
|
-
if (columns && columns.length > 0)
|
|
503
|
-
fetchUrl.searchParams.set(COLUMNS_QUERY_PARAM, columns.join(`,`));
|
|
504
|
-
fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
|
|
505
|
-
if (__privateGet(this, _isUpToDate)) {
|
|
506
|
-
fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
|
|
507
|
-
fetchUrl.searchParams.set(
|
|
508
|
-
LIVE_CACHE_BUSTER_QUERY_PARAM,
|
|
509
|
-
__privateGet(this, _liveCacheBuster)
|
|
510
|
-
);
|
|
511
|
-
}
|
|
512
|
-
if (__privateGet(this, _shapeHandle)) {
|
|
513
|
-
fetchUrl.searchParams.set(
|
|
514
|
-
SHAPE_HANDLE_QUERY_PARAM,
|
|
515
|
-
__privateGet(this, _shapeHandle)
|
|
516
|
-
);
|
|
517
|
-
}
|
|
518
|
-
if (__privateGet(this, _databaseId)) {
|
|
519
|
-
fetchUrl.searchParams.set(DATABASE_ID_QUERY_PARAM, __privateGet(this, _databaseId));
|
|
520
|
-
}
|
|
521
|
-
if (((_a = __privateGet(this, _replica)) != null ? _a : _ShapeStream.Replica.DEFAULT) != _ShapeStream.Replica.DEFAULT) {
|
|
522
|
-
fetchUrl.searchParams.set(REPLICA_PARAM, __privateGet(this, _replica));
|
|
523
|
-
}
|
|
524
|
-
let response;
|
|
525
|
-
try {
|
|
526
|
-
response = await __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
|
|
527
|
-
signal,
|
|
528
|
-
headers: this.options.headers
|
|
529
|
-
});
|
|
530
|
-
__privateSet(this, _connected, true);
|
|
531
|
-
} catch (e) {
|
|
532
|
-
if (e instanceof FetchBackoffAbortError) break;
|
|
533
|
-
if (e instanceof MissingHeadersError) throw e;
|
|
534
|
-
if (!(e instanceof FetchError)) throw e;
|
|
535
|
-
if (e.status == 409) {
|
|
536
|
-
const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER];
|
|
537
|
-
__privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
|
|
538
|
-
await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
|
|
539
|
-
continue;
|
|
540
|
-
} else if (e.status >= 400 && e.status < 500) {
|
|
541
|
-
__privateMethod(this, _ShapeStream_instances, sendErrorToUpToDateSubscribers_fn).call(this, e);
|
|
542
|
-
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
|
|
543
|
-
throw e;
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
const { headers, status } = response;
|
|
547
|
-
const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
|
|
548
|
-
if (shapeHandle) {
|
|
549
|
-
__privateSet(this, _shapeHandle, shapeHandle);
|
|
550
|
-
}
|
|
551
|
-
const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
|
|
552
|
-
if (lastOffset) {
|
|
553
|
-
__privateSet(this, _lastOffset, lastOffset);
|
|
554
|
-
}
|
|
555
|
-
const liveCacheBuster = headers.get(LIVE_CACHE_BUSTER_HEADER);
|
|
556
|
-
if (liveCacheBuster) {
|
|
557
|
-
__privateSet(this, _liveCacheBuster, liveCacheBuster);
|
|
558
|
-
}
|
|
559
|
-
const getSchema = () => {
|
|
560
|
-
const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
|
|
561
|
-
return schemaHeader ? JSON.parse(schemaHeader) : {};
|
|
562
|
-
};
|
|
563
|
-
__privateSet(this, _schema, (_b = __privateGet(this, _schema)) != null ? _b : getSchema());
|
|
564
|
-
const messages = status === 204 ? `[]` : await response.text();
|
|
565
|
-
if (status === 204) {
|
|
566
|
-
__privateSet(this, _lastSyncedAt, Date.now());
|
|
567
|
-
}
|
|
568
|
-
const batch = __privateGet(this, _messageParser).parse(messages, __privateGet(this, _schema));
|
|
569
|
-
if (batch.length > 0) {
|
|
570
|
-
const prevUpToDate = __privateGet(this, _isUpToDate);
|
|
571
|
-
const lastMessage = batch[batch.length - 1];
|
|
572
|
-
if (isUpToDateMessage(lastMessage)) {
|
|
573
|
-
__privateSet(this, _lastSyncedAt, Date.now());
|
|
574
|
-
__privateSet(this, _isUpToDate, true);
|
|
575
|
-
}
|
|
576
|
-
await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
|
|
577
|
-
if (!prevUpToDate && __privateGet(this, _isUpToDate)) {
|
|
578
|
-
__privateMethod(this, _ShapeStream_instances, notifyUpToDateSubscribers_fn).call(this);
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
} catch (err) {
|
|
583
|
-
__privateSet(this, _error, err);
|
|
584
|
-
} finally {
|
|
585
|
-
__privateSet(this, _connected, false);
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
subscribe(callback, onError) {
|
|
518
|
+
subscribe(callback, onError = () => {
|
|
519
|
+
}) {
|
|
589
520
|
const subscriptionId = Math.random();
|
|
590
521
|
__privateGet(this, _subscribers).set(subscriptionId, [callback, onError]);
|
|
591
522
|
return () => {
|
|
@@ -595,16 +526,6 @@ var _ShapeStream = class _ShapeStream {
|
|
|
595
526
|
unsubscribeAll() {
|
|
596
527
|
__privateGet(this, _subscribers).clear();
|
|
597
528
|
}
|
|
598
|
-
subscribeOnceToUpToDate(callback, error) {
|
|
599
|
-
const subscriptionId = Math.random();
|
|
600
|
-
__privateGet(this, _upToDateSubscribers).set(subscriptionId, [callback, error]);
|
|
601
|
-
return () => {
|
|
602
|
-
__privateGet(this, _upToDateSubscribers).delete(subscriptionId);
|
|
603
|
-
};
|
|
604
|
-
}
|
|
605
|
-
unsubscribeAllUpToDateSubscribers() {
|
|
606
|
-
__privateGet(this, _upToDateSubscribers).clear();
|
|
607
|
-
}
|
|
608
529
|
/** Unix time at which we last synced. Undefined when `isLoading` is true. */
|
|
609
530
|
lastSyncedAt() {
|
|
610
531
|
return __privateGet(this, _lastSyncedAt);
|
|
@@ -620,13 +541,13 @@ var _ShapeStream = class _ShapeStream {
|
|
|
620
541
|
}
|
|
621
542
|
/** True during initial fetch. False afterwise. */
|
|
622
543
|
isLoading() {
|
|
623
|
-
return !this
|
|
544
|
+
return !__privateGet(this, _isUpToDate);
|
|
624
545
|
}
|
|
625
546
|
};
|
|
547
|
+
_error = new WeakMap();
|
|
626
548
|
_fetchClient2 = new WeakMap();
|
|
627
549
|
_messageParser = new WeakMap();
|
|
628
550
|
_subscribers = new WeakMap();
|
|
629
|
-
_upToDateSubscribers = new WeakMap();
|
|
630
551
|
_lastOffset = new WeakMap();
|
|
631
552
|
_liveCacheBuster = new WeakMap();
|
|
632
553
|
_lastSyncedAt = new WeakMap();
|
|
@@ -635,9 +556,125 @@ _connected = new WeakMap();
|
|
|
635
556
|
_shapeHandle = new WeakMap();
|
|
636
557
|
_databaseId = new WeakMap();
|
|
637
558
|
_schema = new WeakMap();
|
|
638
|
-
|
|
559
|
+
_onError = new WeakMap();
|
|
639
560
|
_replica = new WeakMap();
|
|
640
561
|
_ShapeStream_instances = new WeakSet();
|
|
562
|
+
start_fn = async function() {
|
|
563
|
+
var _a, _b, _c;
|
|
564
|
+
try {
|
|
565
|
+
while (!((_a = this.options.signal) == null ? void 0 : _a.aborted) && !__privateGet(this, _isUpToDate) || this.options.subscribe) {
|
|
566
|
+
const { url, table, where, columns, signal } = this.options;
|
|
567
|
+
const fetchUrl = new URL(url);
|
|
568
|
+
if (this.options.params) {
|
|
569
|
+
const reservedParams = Object.keys(this.options.params).filter(
|
|
570
|
+
(key) => RESERVED_PARAMS.has(key)
|
|
571
|
+
);
|
|
572
|
+
if (reservedParams.length > 0) {
|
|
573
|
+
throw new Error(
|
|
574
|
+
`Cannot use reserved Electric parameter names in custom params: ${reservedParams.join(`, `)}`
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
for (const [key, value] of Object.entries(this.options.params)) {
|
|
578
|
+
fetchUrl.searchParams.set(key, value);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
if (table) fetchUrl.searchParams.set(TABLE_QUERY_PARAM, table);
|
|
582
|
+
if (where) fetchUrl.searchParams.set(WHERE_QUERY_PARAM, where);
|
|
583
|
+
if (columns && columns.length > 0)
|
|
584
|
+
fetchUrl.searchParams.set(COLUMNS_QUERY_PARAM, columns.join(`,`));
|
|
585
|
+
fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
|
|
586
|
+
if (__privateGet(this, _isUpToDate)) {
|
|
587
|
+
fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
|
|
588
|
+
fetchUrl.searchParams.set(
|
|
589
|
+
LIVE_CACHE_BUSTER_QUERY_PARAM,
|
|
590
|
+
__privateGet(this, _liveCacheBuster)
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
if (__privateGet(this, _shapeHandle)) {
|
|
594
|
+
fetchUrl.searchParams.set(
|
|
595
|
+
SHAPE_HANDLE_QUERY_PARAM,
|
|
596
|
+
__privateGet(this, _shapeHandle)
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
if (__privateGet(this, _databaseId)) {
|
|
600
|
+
fetchUrl.searchParams.set(DATABASE_ID_QUERY_PARAM, __privateGet(this, _databaseId));
|
|
601
|
+
}
|
|
602
|
+
if (((_b = __privateGet(this, _replica)) != null ? _b : _ShapeStream.Replica.DEFAULT) != _ShapeStream.Replica.DEFAULT) {
|
|
603
|
+
fetchUrl.searchParams.set(REPLICA_PARAM, __privateGet(this, _replica));
|
|
604
|
+
}
|
|
605
|
+
let response;
|
|
606
|
+
try {
|
|
607
|
+
response = await __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
|
|
608
|
+
signal,
|
|
609
|
+
headers: this.options.headers
|
|
610
|
+
});
|
|
611
|
+
__privateSet(this, _connected, true);
|
|
612
|
+
} catch (e) {
|
|
613
|
+
if (e instanceof FetchBackoffAbortError) break;
|
|
614
|
+
if (!(e instanceof FetchError)) throw e;
|
|
615
|
+
if (e.status == 409) {
|
|
616
|
+
const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER];
|
|
617
|
+
__privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
|
|
618
|
+
await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
|
|
619
|
+
continue;
|
|
620
|
+
} else if (e.status >= 400 && e.status < 500) {
|
|
621
|
+
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
|
|
622
|
+
throw e;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
const { headers, status } = response;
|
|
626
|
+
const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
|
|
627
|
+
if (shapeHandle) {
|
|
628
|
+
__privateSet(this, _shapeHandle, shapeHandle);
|
|
629
|
+
}
|
|
630
|
+
const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
|
|
631
|
+
if (lastOffset) {
|
|
632
|
+
__privateSet(this, _lastOffset, lastOffset);
|
|
633
|
+
}
|
|
634
|
+
const liveCacheBuster = headers.get(LIVE_CACHE_BUSTER_HEADER);
|
|
635
|
+
if (liveCacheBuster) {
|
|
636
|
+
__privateSet(this, _liveCacheBuster, liveCacheBuster);
|
|
637
|
+
}
|
|
638
|
+
const getSchema = () => {
|
|
639
|
+
const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
|
|
640
|
+
return schemaHeader ? JSON.parse(schemaHeader) : {};
|
|
641
|
+
};
|
|
642
|
+
__privateSet(this, _schema, (_c = __privateGet(this, _schema)) != null ? _c : getSchema());
|
|
643
|
+
const messages = status === 204 ? `[]` : await response.text();
|
|
644
|
+
if (status === 204) {
|
|
645
|
+
__privateSet(this, _lastSyncedAt, Date.now());
|
|
646
|
+
}
|
|
647
|
+
const batch = __privateGet(this, _messageParser).parse(messages, __privateGet(this, _schema));
|
|
648
|
+
if (batch.length > 0) {
|
|
649
|
+
const lastMessage = batch[batch.length - 1];
|
|
650
|
+
if (isUpToDateMessage(lastMessage)) {
|
|
651
|
+
__privateSet(this, _lastSyncedAt, Date.now());
|
|
652
|
+
__privateSet(this, _isUpToDate, true);
|
|
653
|
+
}
|
|
654
|
+
await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
} catch (err) {
|
|
658
|
+
__privateSet(this, _error, err);
|
|
659
|
+
if (__privateGet(this, _onError)) {
|
|
660
|
+
const retryOpts = await __privateGet(this, _onError).call(this, err);
|
|
661
|
+
if (typeof retryOpts === `object`) {
|
|
662
|
+
__privateMethod(this, _ShapeStream_instances, reset_fn).call(this);
|
|
663
|
+
if (`params` in retryOpts) {
|
|
664
|
+
this.options.params = retryOpts.params;
|
|
665
|
+
}
|
|
666
|
+
if (`headers` in retryOpts) {
|
|
667
|
+
this.options.headers = retryOpts.headers;
|
|
668
|
+
}
|
|
669
|
+
__privateMethod(this, _ShapeStream_instances, start_fn).call(this);
|
|
670
|
+
}
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
throw err;
|
|
674
|
+
} finally {
|
|
675
|
+
__privateSet(this, _connected, false);
|
|
676
|
+
}
|
|
677
|
+
};
|
|
641
678
|
publish_fn = async function(messages) {
|
|
642
679
|
await Promise.all(
|
|
643
680
|
Array.from(__privateGet(this, _subscribers).values()).map(async ([callback, __]) => {
|
|
@@ -656,24 +693,14 @@ sendErrorToSubscribers_fn = function(error) {
|
|
|
656
693
|
errorFn == null ? void 0 : errorFn(error);
|
|
657
694
|
});
|
|
658
695
|
};
|
|
659
|
-
notifyUpToDateSubscribers_fn = function() {
|
|
660
|
-
__privateGet(this, _upToDateSubscribers).forEach(([callback]) => {
|
|
661
|
-
callback();
|
|
662
|
-
});
|
|
663
|
-
};
|
|
664
|
-
sendErrorToUpToDateSubscribers_fn = function(error) {
|
|
665
|
-
__privateGet(this, _upToDateSubscribers).forEach(
|
|
666
|
-
([_, errorCallback]) => errorCallback(error)
|
|
667
|
-
);
|
|
668
|
-
};
|
|
669
696
|
/**
|
|
670
697
|
* Resets the state of the stream, optionally with a provided
|
|
671
698
|
* shape handle
|
|
672
699
|
*/
|
|
673
|
-
reset_fn = function(
|
|
700
|
+
reset_fn = function(handle) {
|
|
674
701
|
__privateSet(this, _lastOffset, `-1`);
|
|
675
702
|
__privateSet(this, _liveCacheBuster, ``);
|
|
676
|
-
__privateSet(this, _shapeHandle,
|
|
703
|
+
__privateSet(this, _shapeHandle, handle);
|
|
677
704
|
__privateSet(this, _isUpToDate, false);
|
|
678
705
|
__privateSet(this, _connected, false);
|
|
679
706
|
__privateSet(this, _schema, void 0);
|
|
@@ -685,26 +712,20 @@ _ShapeStream.Replica = {
|
|
|
685
712
|
var ShapeStream = _ShapeStream;
|
|
686
713
|
function validateOptions(options) {
|
|
687
714
|
if (!options.url) {
|
|
688
|
-
throw new
|
|
715
|
+
throw new MissingShapeUrlError();
|
|
689
716
|
}
|
|
690
717
|
if (options.signal && !(options.signal instanceof AbortSignal)) {
|
|
691
|
-
throw new
|
|
692
|
-
`Invalid signal option. It must be an instance of AbortSignal.`
|
|
693
|
-
);
|
|
718
|
+
throw new InvalidSignalError();
|
|
694
719
|
}
|
|
695
|
-
if (options.offset !== void 0 && options.offset !== `-1` && !options.
|
|
696
|
-
throw new
|
|
697
|
-
`shapeHandle is required if this isn't an initial fetch (i.e. offset > -1)`
|
|
698
|
-
);
|
|
720
|
+
if (options.offset !== void 0 && options.offset !== `-1` && !options.handle) {
|
|
721
|
+
throw new MissingShapeHandleError();
|
|
699
722
|
}
|
|
700
723
|
if (options.params) {
|
|
701
724
|
const reservedParams = Object.keys(options.params).filter(
|
|
702
725
|
(key) => RESERVED_PARAMS.has(key)
|
|
703
726
|
);
|
|
704
727
|
if (reservedParams.length > 0) {
|
|
705
|
-
throw new
|
|
706
|
-
`Cannot use reserved Electric parameter names in custom params: ${reservedParams.join(`, `)}`
|
|
707
|
-
);
|
|
728
|
+
throw new ReservedParamError(reservedParams);
|
|
708
729
|
}
|
|
709
730
|
}
|
|
710
731
|
return;
|
|
@@ -725,15 +746,6 @@ var Shape = class {
|
|
|
725
746
|
__privateMethod(this, _Shape_instances, process_fn).bind(this),
|
|
726
747
|
__privateMethod(this, _Shape_instances, handleError_fn).bind(this)
|
|
727
748
|
);
|
|
728
|
-
const unsubscribe = __privateGet(this, _stream).subscribeOnceToUpToDate(
|
|
729
|
-
() => {
|
|
730
|
-
unsubscribe();
|
|
731
|
-
},
|
|
732
|
-
(e) => {
|
|
733
|
-
__privateMethod(this, _Shape_instances, handleError_fn).call(this, e);
|
|
734
|
-
throw e;
|
|
735
|
-
}
|
|
736
|
-
);
|
|
737
749
|
}
|
|
738
750
|
get isUpToDate() {
|
|
739
751
|
return __privateGet(this, _stream).isUpToDate;
|
|
@@ -741,6 +753,9 @@ var Shape = class {
|
|
|
741
753
|
get lastOffset() {
|
|
742
754
|
return __privateGet(this, _stream).lastOffset;
|
|
743
755
|
}
|
|
756
|
+
get handle() {
|
|
757
|
+
return __privateGet(this, _stream).shapeHandle;
|
|
758
|
+
}
|
|
744
759
|
get rows() {
|
|
745
760
|
return this.value.then((v) => Array.from(v.values()));
|
|
746
761
|
}
|