@supabase/postgrest-js 2.114.0 → 2.115.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.cjs +210 -71
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +44 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +210 -71
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/PostgrestBuilder.ts +27 -125
- package/src/PostgrestClient.ts +137 -0
- package/src/fetchWithRetry.ts +141 -0
- package/src/index.ts +1 -0
- package/src/types/types.ts +22 -0
- package/src/version.ts +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,32 +1,3 @@
|
|
|
1
|
-
//#region src/types/common/common.ts
|
|
2
|
-
/**
|
|
3
|
-
* Default number of retry attempts.
|
|
4
|
-
*/
|
|
5
|
-
const DEFAULT_MAX_RETRIES = 3;
|
|
6
|
-
/**
|
|
7
|
-
* Default exponential backoff delay function.
|
|
8
|
-
* Delays: 1s, 2s, 4s, 8s, ... (max 30s)
|
|
9
|
-
*
|
|
10
|
-
* @param attemptIndex - Zero-based index of the retry attempt
|
|
11
|
-
* @returns Delay in milliseconds before the next retry
|
|
12
|
-
*/
|
|
13
|
-
const getRetryDelay = (attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4);
|
|
14
|
-
/**
|
|
15
|
-
* Status codes that are safe to retry.
|
|
16
|
-
* 520 = Cloudflare timeout/connection errors (transient)
|
|
17
|
-
* 503 = PostgREST schema cache not yet loaded (transient, signals retry via Retry-After header)
|
|
18
|
-
*/
|
|
19
|
-
const RETRYABLE_STATUS_CODES = [520, 503];
|
|
20
|
-
/**
|
|
21
|
-
* HTTP methods that are safe to retry (idempotent operations).
|
|
22
|
-
*/
|
|
23
|
-
const RETRYABLE_METHODS = [
|
|
24
|
-
"GET",
|
|
25
|
-
"HEAD",
|
|
26
|
-
"OPTIONS"
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
//#endregion
|
|
30
1
|
//#region src/PostgrestError.ts
|
|
31
2
|
/**
|
|
32
3
|
* Error format
|
|
@@ -84,6 +55,35 @@ var PostgrestError = class extends Error {
|
|
|
84
55
|
}
|
|
85
56
|
};
|
|
86
57
|
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/types/common/common.ts
|
|
60
|
+
/**
|
|
61
|
+
* Default number of retry attempts.
|
|
62
|
+
*/
|
|
63
|
+
const DEFAULT_MAX_RETRIES = 3;
|
|
64
|
+
/**
|
|
65
|
+
* Default exponential backoff delay function.
|
|
66
|
+
* Delays: 1s, 2s, 4s, 8s, ... (max 30s)
|
|
67
|
+
*
|
|
68
|
+
* @param attemptIndex - Zero-based index of the retry attempt
|
|
69
|
+
* @returns Delay in milliseconds before the next retry
|
|
70
|
+
*/
|
|
71
|
+
const getRetryDelay = (attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4);
|
|
72
|
+
/**
|
|
73
|
+
* Status codes that are safe to retry.
|
|
74
|
+
* 520 = Cloudflare timeout/connection errors (transient)
|
|
75
|
+
* 503 = PostgREST schema cache not yet loaded (transient, signals retry via Retry-After header)
|
|
76
|
+
*/
|
|
77
|
+
const RETRYABLE_STATUS_CODES = [520, 503];
|
|
78
|
+
/**
|
|
79
|
+
* HTTP methods that are safe to retry (idempotent operations).
|
|
80
|
+
*/
|
|
81
|
+
const RETRYABLE_METHODS = [
|
|
82
|
+
"GET",
|
|
83
|
+
"HEAD",
|
|
84
|
+
"OPTIONS"
|
|
85
|
+
];
|
|
86
|
+
|
|
87
87
|
//#endregion
|
|
88
88
|
//#region \0@oxc-project+runtime@0.103.0/helpers/typeof.js
|
|
89
89
|
function _typeof(o) {
|
|
@@ -151,7 +151,7 @@ function _objectSpread2(e) {
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
//#endregion
|
|
154
|
-
//#region src/
|
|
154
|
+
//#region src/fetchWithRetry.ts
|
|
155
155
|
/**
|
|
156
156
|
* Sleep for a given number of milliseconds.
|
|
157
157
|
* If an AbortSignal is provided, the sleep resolves early when the signal is aborted.
|
|
@@ -182,6 +182,56 @@ function shouldRetry(method, status, attemptCount, retryEnabled) {
|
|
|
182
182
|
if (!RETRYABLE_STATUS_CODES.includes(status)) return false;
|
|
183
183
|
return true;
|
|
184
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Perform a request with the retry policy shared by every PostgREST call.
|
|
187
|
+
*
|
|
188
|
+
* Idempotent methods (GET, HEAD, OPTIONS) are retried up to
|
|
189
|
+
* `DEFAULT_MAX_RETRIES` times when the fetch rejects or the server answers
|
|
190
|
+
* with a retryable status (503, 520). The wait honours the `Retry-After`
|
|
191
|
+
* header when present and backs off exponentially otherwise. Retried
|
|
192
|
+
* attempts carry an `X-Retry-Count` header. Aborted requests and
|
|
193
|
+
* non-idempotent methods are never retried: their rejection propagates
|
|
194
|
+
* unchanged. A response body is drained before its request is retried.
|
|
195
|
+
*/
|
|
196
|
+
async function fetchWithRetry(fetchImpl, url, request, retryEnabled) {
|
|
197
|
+
let attemptCount = 0;
|
|
198
|
+
while (true) {
|
|
199
|
+
const headers = _objectSpread2({}, request.headers);
|
|
200
|
+
if (attemptCount > 0) headers["X-Retry-Count"] = String(attemptCount);
|
|
201
|
+
let res;
|
|
202
|
+
try {
|
|
203
|
+
res = await fetchImpl(url, {
|
|
204
|
+
method: request.method,
|
|
205
|
+
headers,
|
|
206
|
+
body: request.body,
|
|
207
|
+
signal: request.signal
|
|
208
|
+
});
|
|
209
|
+
} catch (fetchError) {
|
|
210
|
+
if ((fetchError === null || fetchError === void 0 ? void 0 : fetchError.name) === "AbortError" || (fetchError === null || fetchError === void 0 ? void 0 : fetchError.code) === "ABORT_ERR") throw fetchError;
|
|
211
|
+
if (!RETRYABLE_METHODS.includes(request.method)) throw fetchError;
|
|
212
|
+
if (retryEnabled && attemptCount < DEFAULT_MAX_RETRIES) {
|
|
213
|
+
const delay = getRetryDelay(attemptCount);
|
|
214
|
+
attemptCount++;
|
|
215
|
+
await sleep(delay, request.signal);
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
throw fetchError;
|
|
219
|
+
}
|
|
220
|
+
if (shouldRetry(request.method, res.status, attemptCount, retryEnabled)) {
|
|
221
|
+
var _res$headers$get, _res$headers;
|
|
222
|
+
const retryAfterHeader = (_res$headers$get = (_res$headers = res.headers) === null || _res$headers === void 0 ? void 0 : _res$headers.get("Retry-After")) !== null && _res$headers$get !== void 0 ? _res$headers$get : null;
|
|
223
|
+
const delay = retryAfterHeader !== null ? Math.max(0, parseInt(retryAfterHeader, 10) || 0) * 1e3 : getRetryDelay(attemptCount);
|
|
224
|
+
await res.text();
|
|
225
|
+
attemptCount++;
|
|
226
|
+
await sleep(delay, request.signal);
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
return res;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
//#endregion
|
|
234
|
+
//#region src/PostgrestBuilder.ts
|
|
185
235
|
var PostgrestBuilder = class {
|
|
186
236
|
/**
|
|
187
237
|
* Creates a builder configured for a specific PostgREST request.
|
|
@@ -350,43 +400,17 @@ var PostgrestBuilder = class {
|
|
|
350
400
|
}
|
|
351
401
|
const _fetch = this.fetch;
|
|
352
402
|
const executeWithRetry = async () => {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
headers,
|
|
365
|
-
body: JSON.stringify(_this.body, (_, value) => typeof value === "bigint" ? value.toString() : value),
|
|
366
|
-
signal: _this.signal
|
|
367
|
-
});
|
|
368
|
-
} catch (fetchError) {
|
|
369
|
-
if ((fetchError === null || fetchError === void 0 ? void 0 : fetchError.name) === "AbortError" || (fetchError === null || fetchError === void 0 ? void 0 : fetchError.code) === "ABORT_ERR") throw fetchError;
|
|
370
|
-
if (!RETRYABLE_METHODS.includes(_this.method)) throw fetchError;
|
|
371
|
-
if (_this.retryEnabled && attemptCount < DEFAULT_MAX_RETRIES) {
|
|
372
|
-
const delay = getRetryDelay(attemptCount);
|
|
373
|
-
attemptCount++;
|
|
374
|
-
await sleep(delay, _this.signal);
|
|
375
|
-
continue;
|
|
376
|
-
}
|
|
377
|
-
throw fetchError;
|
|
378
|
-
}
|
|
379
|
-
if (shouldRetry(_this.method, res$1.status, attemptCount, _this.retryEnabled)) {
|
|
380
|
-
var _res$headers$get, _res$headers;
|
|
381
|
-
const retryAfterHeader = (_res$headers$get = (_res$headers = res$1.headers) === null || _res$headers === void 0 ? void 0 : _res$headers.get("Retry-After")) !== null && _res$headers$get !== void 0 ? _res$headers$get : null;
|
|
382
|
-
const delay = retryAfterHeader !== null ? Math.max(0, parseInt(retryAfterHeader, 10) || 0) * 1e3 : getRetryDelay(attemptCount);
|
|
383
|
-
await res$1.text();
|
|
384
|
-
attemptCount++;
|
|
385
|
-
await sleep(delay, _this.signal);
|
|
386
|
-
continue;
|
|
387
|
-
}
|
|
388
|
-
return await _this.processResponse(res$1);
|
|
389
|
-
}
|
|
403
|
+
const headers = {};
|
|
404
|
+
_this.headers.forEach((value, key) => {
|
|
405
|
+
headers[key] = value;
|
|
406
|
+
});
|
|
407
|
+
const res$1 = await fetchWithRetry(_fetch, _this.url.toString(), {
|
|
408
|
+
method: _this.method,
|
|
409
|
+
headers,
|
|
410
|
+
body: JSON.stringify(_this.body, (_, value) => typeof value === "bigint" ? value.toString() : value),
|
|
411
|
+
signal: _this.signal
|
|
412
|
+
}, _this.retryEnabled);
|
|
413
|
+
return await _this.processResponse(res$1);
|
|
390
414
|
};
|
|
391
415
|
let res = executeWithRetry();
|
|
392
416
|
if (!this.shouldThrowOnError) res = res.catch((fetchError) => {
|
|
@@ -444,7 +468,7 @@ var PostgrestBuilder = class {
|
|
|
444
468
|
let status = res.status;
|
|
445
469
|
let statusText = res.statusText;
|
|
446
470
|
if (res.ok) {
|
|
447
|
-
var _this$headers$get2, _res$headers$
|
|
471
|
+
var _this$headers$get2, _res$headers$get;
|
|
448
472
|
if (_this2.method !== "HEAD") {
|
|
449
473
|
var _this$headers$get;
|
|
450
474
|
const body = await res.text();
|
|
@@ -464,7 +488,7 @@ var PostgrestBuilder = class {
|
|
|
464
488
|
}
|
|
465
489
|
}
|
|
466
490
|
const countHeader = (_this$headers$get2 = _this2.headers.get("Prefer")) === null || _this$headers$get2 === void 0 ? void 0 : _this$headers$get2.match(/count=(exact|planned|estimated)/);
|
|
467
|
-
const contentRange = (_res$headers$
|
|
491
|
+
const contentRange = (_res$headers$get = res.headers.get("content-range")) === null || _res$headers$get === void 0 ? void 0 : _res$headers$get.split("/");
|
|
468
492
|
if (countHeader && contentRange && contentRange.length > 1) count = parseInt(contentRange[1]);
|
|
469
493
|
if (_this2.isMaybeSingle && Array.isArray(data)) if (data.length > 1) {
|
|
470
494
|
error = {
|
|
@@ -3561,6 +3585,54 @@ var PostgrestQueryBuilder = class {
|
|
|
3561
3585
|
//#endregion
|
|
3562
3586
|
//#region src/PostgrestClient.ts
|
|
3563
3587
|
/**
|
|
3588
|
+
* Build the error for a failed OpenAPI request. PostgREST answers with a JSON
|
|
3589
|
+
* error object when it produced the failure itself; proxies and disabled
|
|
3590
|
+
* OpenAPI output answer with plain text or an empty body, in which case the
|
|
3591
|
+
* body (or, failing that, the status text) becomes the message.
|
|
3592
|
+
*/
|
|
3593
|
+
function toOpenApiError(body, statusText) {
|
|
3594
|
+
try {
|
|
3595
|
+
const parsed = JSON.parse(body);
|
|
3596
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
3597
|
+
var _parsed$message, _parsed$details, _parsed$hint, _parsed$code;
|
|
3598
|
+
return new PostgrestError({
|
|
3599
|
+
message: String((_parsed$message = parsed.message) !== null && _parsed$message !== void 0 ? _parsed$message : body),
|
|
3600
|
+
details: (_parsed$details = parsed.details) !== null && _parsed$details !== void 0 ? _parsed$details : "",
|
|
3601
|
+
hint: (_parsed$hint = parsed.hint) !== null && _parsed$hint !== void 0 ? _parsed$hint : "",
|
|
3602
|
+
code: (_parsed$code = parsed.code) !== null && _parsed$code !== void 0 ? _parsed$code : ""
|
|
3603
|
+
});
|
|
3604
|
+
}
|
|
3605
|
+
} catch (_unused) {}
|
|
3606
|
+
return new PostgrestError({
|
|
3607
|
+
message: body || statusText,
|
|
3608
|
+
details: "",
|
|
3609
|
+
hint: "",
|
|
3610
|
+
code: ""
|
|
3611
|
+
});
|
|
3612
|
+
}
|
|
3613
|
+
/**
|
|
3614
|
+
* Build the response for a request that yielded no readable body: the fetch
|
|
3615
|
+
* itself rejected (no status is known, so it is 0), or the body stream failed
|
|
3616
|
+
* while being read (the response status is preserved).
|
|
3617
|
+
*/
|
|
3618
|
+
function toTransportFailure(cause, status, statusText) {
|
|
3619
|
+
var _err$name;
|
|
3620
|
+
const err = cause;
|
|
3621
|
+
return {
|
|
3622
|
+
success: false,
|
|
3623
|
+
error: new PostgrestError({
|
|
3624
|
+
message: `${(_err$name = err === null || err === void 0 ? void 0 : err.name) !== null && _err$name !== void 0 ? _err$name : "FetchError"}: ${err === null || err === void 0 ? void 0 : err.message}`,
|
|
3625
|
+
details: "",
|
|
3626
|
+
hint: "",
|
|
3627
|
+
code: ""
|
|
3628
|
+
}),
|
|
3629
|
+
data: null,
|
|
3630
|
+
count: null,
|
|
3631
|
+
status,
|
|
3632
|
+
statusText
|
|
3633
|
+
};
|
|
3634
|
+
}
|
|
3635
|
+
/**
|
|
3564
3636
|
* PostgREST client.
|
|
3565
3637
|
*
|
|
3566
3638
|
* @typeParam Database - Types for the schema from the [type
|
|
@@ -3669,6 +3741,73 @@ var PostgrestClient = class PostgrestClient {
|
|
|
3669
3741
|
});
|
|
3670
3742
|
}
|
|
3671
3743
|
/**
|
|
3744
|
+
* Fetch the OpenAPI description PostgREST publishes for this client's schema.
|
|
3745
|
+
*
|
|
3746
|
+
* The document lists only the tables, views and functions the caller's role
|
|
3747
|
+
* holds privileges on; PostgREST applies that filtering server-side. The
|
|
3748
|
+
* schema is the one this client was created with, so call `.schema()` first
|
|
3749
|
+
* to describe a different one. Transient failures are retried according to
|
|
3750
|
+
* the client's `retry` option, like any other idempotent request.
|
|
3751
|
+
*
|
|
3752
|
+
* @example
|
|
3753
|
+
* ```ts
|
|
3754
|
+
* const { data, error } = await supabase.getOpenApiSpec()
|
|
3755
|
+
* ```
|
|
3756
|
+
*
|
|
3757
|
+
* @example Describe a schema other than the client default
|
|
3758
|
+
* ```ts
|
|
3759
|
+
* const { data, error } = await supabase.schema('billing').getOpenApiSpec()
|
|
3760
|
+
* ```
|
|
3761
|
+
*
|
|
3762
|
+
* @category Database
|
|
3763
|
+
*/
|
|
3764
|
+
async getOpenApiSpec() {
|
|
3765
|
+
var _this = this;
|
|
3766
|
+
var _this$fetch;
|
|
3767
|
+
const headers = new Headers(_this.headers);
|
|
3768
|
+
headers.set("Accept", "application/openapi+json");
|
|
3769
|
+
if (_this.schemaName) headers.set("Accept-Profile", _this.schemaName);
|
|
3770
|
+
const requestHeaders = {};
|
|
3771
|
+
headers.forEach((value, key) => {
|
|
3772
|
+
requestHeaders[key] = value;
|
|
3773
|
+
});
|
|
3774
|
+
const fetchImpl = (_this$fetch = _this.fetch) !== null && _this$fetch !== void 0 ? _this$fetch : globalThis.fetch;
|
|
3775
|
+
let res;
|
|
3776
|
+
try {
|
|
3777
|
+
var _this$retry;
|
|
3778
|
+
res = await fetchWithRetry(fetchImpl, `${_this.url}/`, {
|
|
3779
|
+
method: "GET",
|
|
3780
|
+
headers: requestHeaders
|
|
3781
|
+
}, (_this$retry = _this.retry) !== null && _this$retry !== void 0 ? _this$retry : true);
|
|
3782
|
+
} catch (fetchError) {
|
|
3783
|
+
return toTransportFailure(fetchError, 0, "");
|
|
3784
|
+
}
|
|
3785
|
+
let body;
|
|
3786
|
+
try {
|
|
3787
|
+
body = await res.text();
|
|
3788
|
+
} catch (readError) {
|
|
3789
|
+
return toTransportFailure(readError, res.status, res.statusText);
|
|
3790
|
+
}
|
|
3791
|
+
if (res.ok) try {
|
|
3792
|
+
return {
|
|
3793
|
+
success: true,
|
|
3794
|
+
error: null,
|
|
3795
|
+
data: JSON.parse(body),
|
|
3796
|
+
count: null,
|
|
3797
|
+
status: res.status,
|
|
3798
|
+
statusText: res.statusText
|
|
3799
|
+
};
|
|
3800
|
+
} catch (_unused2) {}
|
|
3801
|
+
return {
|
|
3802
|
+
success: false,
|
|
3803
|
+
error: toOpenApiError(body, res.statusText),
|
|
3804
|
+
data: null,
|
|
3805
|
+
count: null,
|
|
3806
|
+
status: res.status,
|
|
3807
|
+
statusText: res.statusText
|
|
3808
|
+
};
|
|
3809
|
+
}
|
|
3810
|
+
/**
|
|
3672
3811
|
* Perform a function call.
|
|
3673
3812
|
*
|
|
3674
3813
|
* @param fn - The function name to call
|
|
@@ -3834,7 +3973,7 @@ var PostgrestClient = class PostgrestClient {
|
|
|
3834
3973
|
* ```
|
|
3835
3974
|
*/
|
|
3836
3975
|
rpc(fn, args = {}, { head = false, get = false, count } = {}) {
|
|
3837
|
-
var _this$
|
|
3976
|
+
var _this$fetch2;
|
|
3838
3977
|
let method;
|
|
3839
3978
|
const url = new URL(`${this.url}/rpc/${fn}`);
|
|
3840
3979
|
let body;
|
|
@@ -3861,7 +4000,7 @@ var PostgrestClient = class PostgrestClient {
|
|
|
3861
4000
|
headers,
|
|
3862
4001
|
schema: this.schemaName,
|
|
3863
4002
|
body,
|
|
3864
|
-
fetch: (_this$
|
|
4003
|
+
fetch: (_this$fetch2 = this.fetch) !== null && _this$fetch2 !== void 0 ? _this$fetch2 : fetch,
|
|
3865
4004
|
urlLengthLimit: this.urlLengthLimit,
|
|
3866
4005
|
retry: this.retry
|
|
3867
4006
|
});
|