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