@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.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/PostgrestBuilder.ts
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
- let attemptCount = 0;
354
- while (true) {
355
- const headers = {};
356
- _this.headers.forEach((value, key) => {
357
- headers[key] = value;
358
- });
359
- if (attemptCount > 0) headers["X-Retry-Count"] = String(attemptCount);
360
- let res$1;
361
- try {
362
- res$1 = await _fetch(_this.url.toString(), {
363
- method: _this.method,
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$get2;
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$get2 = res.headers.get("content-range")) === null || _res$headers$get2 === void 0 ? void 0 : _res$headers$get2.split("/");
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$fetch;
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$fetch = this.fetch) !== null && _this$fetch !== void 0 ? _this$fetch : fetch,
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
  });