@supabase/postgrest-js 2.118.0 → 2.119.0-canary.1
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 +56 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -4
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +34 -4
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +56 -29
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/PostgrestClient.ts +87 -49
- package/src/index.ts +1 -0
- package/src/types/types.ts +14 -1
- package/src/version.ts +1 -1
package/package.json
CHANGED
package/src/PostgrestClient.ts
CHANGED
|
@@ -6,6 +6,7 @@ import PostgrestError from './PostgrestError'
|
|
|
6
6
|
import { fetchWithRetry } from './fetchWithRetry'
|
|
7
7
|
import {
|
|
8
8
|
PostgrestOpenApiSpec,
|
|
9
|
+
PostgrestQueryBuilderOptions,
|
|
9
10
|
PostgrestResponseFailure,
|
|
10
11
|
PostgrestSingleResponse,
|
|
11
12
|
} from './types/types'
|
|
@@ -59,6 +60,51 @@ function toTransportFailure(
|
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Bounds every call of `fetch` to `timeout` milliseconds by aborting it through
|
|
65
|
+
* an `AbortController`. A signal already present on the request keeps working:
|
|
66
|
+
* its abort also aborts the timed request. A missing or non-positive timeout
|
|
67
|
+
* returns `fetch` unchanged.
|
|
68
|
+
*/
|
|
69
|
+
function withTimeout(fetch: Fetch, timeout?: number): Fetch {
|
|
70
|
+
if (timeout === undefined || timeout <= 0) return fetch
|
|
71
|
+
|
|
72
|
+
return (input, init) => {
|
|
73
|
+
const controller = new AbortController()
|
|
74
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout)
|
|
75
|
+
|
|
76
|
+
// Merge abort signals if one already exists
|
|
77
|
+
const existingSignal = init?.signal
|
|
78
|
+
if (existingSignal) {
|
|
79
|
+
// If the existing signal is already aborted, use it directly
|
|
80
|
+
if (existingSignal.aborted) {
|
|
81
|
+
clearTimeout(timeoutId)
|
|
82
|
+
return fetch(input, init)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Listen to existing signal and abort our controller too
|
|
86
|
+
const abortHandler = () => {
|
|
87
|
+
clearTimeout(timeoutId)
|
|
88
|
+
controller.abort()
|
|
89
|
+
}
|
|
90
|
+
existingSignal.addEventListener('abort', abortHandler, { once: true })
|
|
91
|
+
|
|
92
|
+
return fetch(input, {
|
|
93
|
+
...init,
|
|
94
|
+
signal: controller.signal,
|
|
95
|
+
}).finally(() => {
|
|
96
|
+
clearTimeout(timeoutId)
|
|
97
|
+
existingSignal.removeEventListener('abort', abortHandler)
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return fetch(input, {
|
|
102
|
+
...init,
|
|
103
|
+
signal: controller.signal,
|
|
104
|
+
}).finally(() => clearTimeout(timeoutId))
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
62
108
|
/**
|
|
63
109
|
* PostgREST client.
|
|
64
110
|
*
|
|
@@ -96,6 +142,11 @@ export default class PostgrestClient<
|
|
|
96
142
|
// Retry configuration - enabled by default
|
|
97
143
|
retry?: boolean
|
|
98
144
|
|
|
145
|
+
protected timeout?: number
|
|
146
|
+
protected wrapFetch?: (fetch: Fetch) => Fetch
|
|
147
|
+
/** The fetch given at construction, before `wrapFetch` and the timeout guard. */
|
|
148
|
+
protected baseFetch?: Fetch
|
|
149
|
+
|
|
99
150
|
// TODO: Add back shouldThrowOnError once we figure out the typings
|
|
100
151
|
/**
|
|
101
152
|
* Creates a PostgREST client.
|
|
@@ -111,6 +162,10 @@ export default class PostgrestClient<
|
|
|
111
162
|
* When enabled, idempotent requests (GET, HEAD, OPTIONS) that fail with network
|
|
112
163
|
* errors or HTTP 503/520 responses will be automatically retried up to 3 times
|
|
113
164
|
* with exponential backoff (1s, 2s, 4s). Defaults to `true`.
|
|
165
|
+
* @param options.wrapFetch - Wraps every fetch this client uses, including a per-request
|
|
166
|
+
* `fetch` passed to `from()`, and is carried over to clients returned by `schema()`.
|
|
167
|
+
* Use it for headers or instrumentation that must reach every request regardless of
|
|
168
|
+
* which fetch performs it.
|
|
114
169
|
* @example Using supabase-js (recommended)
|
|
115
170
|
* ```ts
|
|
116
171
|
* import { createClient } from '@supabase/supabase-js'
|
|
@@ -145,6 +200,7 @@ export default class PostgrestClient<
|
|
|
145
200
|
timeout,
|
|
146
201
|
urlLengthLimit = 8000,
|
|
147
202
|
retry,
|
|
203
|
+
wrapFetch,
|
|
148
204
|
}: {
|
|
149
205
|
headers?: HeadersInit
|
|
150
206
|
schema?: SchemaName
|
|
@@ -152,72 +208,52 @@ export default class PostgrestClient<
|
|
|
152
208
|
timeout?: number
|
|
153
209
|
urlLengthLimit?: number
|
|
154
210
|
retry?: boolean
|
|
211
|
+
wrapFetch?: (fetch: Fetch) => Fetch
|
|
155
212
|
} = {}
|
|
156
213
|
) {
|
|
157
214
|
this.url = url
|
|
158
215
|
this.headers = new Headers(headers)
|
|
159
216
|
this.schemaName = schema
|
|
160
217
|
this.urlLengthLimit = urlLengthLimit
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if (timeout !== undefined && timeout > 0) {
|
|
166
|
-
this.fetch = (input, init) => {
|
|
167
|
-
const controller = new AbortController()
|
|
168
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout)
|
|
169
|
-
|
|
170
|
-
// Merge abort signals if one already exists
|
|
171
|
-
const existingSignal = init?.signal
|
|
172
|
-
if (existingSignal) {
|
|
173
|
-
// If the existing signal is already aborted, use it directly
|
|
174
|
-
if (existingSignal.aborted) {
|
|
175
|
-
clearTimeout(timeoutId)
|
|
176
|
-
return originalFetch(input, init)
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Listen to existing signal and abort our controller too
|
|
180
|
-
const abortHandler = () => {
|
|
181
|
-
clearTimeout(timeoutId)
|
|
182
|
-
controller.abort()
|
|
183
|
-
}
|
|
184
|
-
existingSignal.addEventListener('abort', abortHandler, { once: true })
|
|
185
|
-
|
|
186
|
-
return originalFetch(input, {
|
|
187
|
-
...init,
|
|
188
|
-
signal: controller.signal,
|
|
189
|
-
}).finally(() => {
|
|
190
|
-
clearTimeout(timeoutId)
|
|
191
|
-
existingSignal.removeEventListener('abort', abortHandler)
|
|
192
|
-
})
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return originalFetch(input, {
|
|
196
|
-
...init,
|
|
197
|
-
signal: controller.signal,
|
|
198
|
-
}).finally(() => clearTimeout(timeoutId))
|
|
199
|
-
}
|
|
200
|
-
} else {
|
|
201
|
-
this.fetch = originalFetch
|
|
202
|
-
}
|
|
218
|
+
this.timeout = timeout
|
|
219
|
+
this.wrapFetch = wrapFetch
|
|
220
|
+
this.baseFetch = fetch ?? globalThis.fetch
|
|
221
|
+
this.fetch = this.baseFetch ? this.decorateFetch(this.baseFetch) : undefined
|
|
203
222
|
this.retry = retry
|
|
204
223
|
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Applies the client's decorations to a fetch implementation: `wrapFetch`
|
|
227
|
+
* first, then the timeout guard, so the timeout bounds the whole wrapped call.
|
|
228
|
+
* The client-level fetch and every per-request `fetch` passed to `from()` go
|
|
229
|
+
* through this.
|
|
230
|
+
*/
|
|
231
|
+
protected decorateFetch(fetch: Fetch): Fetch {
|
|
232
|
+
const wrapped = this.wrapFetch ? this.wrapFetch(fetch) : fetch
|
|
233
|
+
return withTimeout(wrapped, this.timeout)
|
|
234
|
+
}
|
|
205
235
|
/**
|
|
206
236
|
* Perform a query on a table or a view.
|
|
207
237
|
*
|
|
208
238
|
* @param relation - The table or view name to query
|
|
239
|
+
* @param options - Per-request options that override client-level defaults
|
|
209
240
|
*
|
|
210
241
|
* @category Database
|
|
211
242
|
*/
|
|
212
243
|
from<
|
|
213
244
|
TableName extends string & keyof Schema['Tables'],
|
|
214
245
|
Table extends Schema['Tables'][TableName],
|
|
215
|
-
>(
|
|
246
|
+
>(
|
|
247
|
+
relation: TableName,
|
|
248
|
+
options?: PostgrestQueryBuilderOptions
|
|
249
|
+
): PostgrestQueryBuilder<ClientOptions, Schema, Table, TableName>
|
|
216
250
|
from<ViewName extends string & keyof Schema['Views'], View extends Schema['Views'][ViewName]>(
|
|
217
|
-
relation: ViewName
|
|
251
|
+
relation: ViewName,
|
|
252
|
+
options?: PostgrestQueryBuilderOptions
|
|
218
253
|
): PostgrestQueryBuilder<ClientOptions, Schema, View, ViewName>
|
|
219
254
|
from(
|
|
220
|
-
relation: (string & keyof Schema['Tables']) | (string & keyof Schema['Views'])
|
|
255
|
+
relation: (string & keyof Schema['Tables']) | (string & keyof Schema['Views']),
|
|
256
|
+
options?: PostgrestQueryBuilderOptions
|
|
221
257
|
): PostgrestQueryBuilder<ClientOptions, Schema, any, any> {
|
|
222
258
|
if (!relation || typeof relation !== 'string' || relation.trim() === '') {
|
|
223
259
|
throw new Error('Invalid relation name: relation must be a non-empty string.')
|
|
@@ -227,9 +263,9 @@ export default class PostgrestClient<
|
|
|
227
263
|
return new PostgrestQueryBuilder(url, {
|
|
228
264
|
headers: new Headers(this.headers),
|
|
229
265
|
schema: this.schemaName,
|
|
230
|
-
fetch: this.fetch,
|
|
231
|
-
urlLengthLimit: this.urlLengthLimit,
|
|
232
|
-
retry: this.retry,
|
|
266
|
+
fetch: options?.fetch ? this.decorateFetch(options.fetch) : this.fetch,
|
|
267
|
+
urlLengthLimit: options?.urlLengthLimit ?? this.urlLengthLimit,
|
|
268
|
+
retry: options?.retry ?? this.retry,
|
|
233
269
|
})
|
|
234
270
|
}
|
|
235
271
|
|
|
@@ -253,7 +289,9 @@ export default class PostgrestClient<
|
|
|
253
289
|
return new PostgrestClient(this.url, {
|
|
254
290
|
headers: this.headers,
|
|
255
291
|
schema,
|
|
256
|
-
fetch: this.
|
|
292
|
+
fetch: this.baseFetch,
|
|
293
|
+
timeout: this.timeout,
|
|
294
|
+
wrapFetch: this.wrapFetch,
|
|
257
295
|
urlLengthLimit: this.urlLengthLimit,
|
|
258
296
|
retry: this.retry,
|
|
259
297
|
})
|
package/src/index.ts
CHANGED
|
@@ -28,6 +28,7 @@ export type {
|
|
|
28
28
|
PostgrestSingleResponse,
|
|
29
29
|
PostgrestMaybeSingleResponse,
|
|
30
30
|
PostgrestOpenApiSpec,
|
|
31
|
+
PostgrestQueryBuilderOptions,
|
|
31
32
|
} from './types/types'
|
|
32
33
|
export type { ClientServerOptions as PostgrestClientOptions } from './types/common/common'
|
|
33
34
|
// https://github.com/supabase/postgrest-js/issues/551
|
package/src/types/types.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import PostgrestError from '../PostgrestError'
|
|
2
2
|
import { ContainsNull } from '../select-query-parser/types'
|
|
3
3
|
import { SelectQueryError } from '../select-query-parser/utils'
|
|
4
|
-
import { ClientServerOptions } from './common/common'
|
|
4
|
+
import { ClientServerOptions, Fetch } from './common/common'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Response format
|
|
@@ -62,6 +62,19 @@ export interface PostgrestOpenApiSpec {
|
|
|
62
62
|
[key: string]: unknown
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Per-request options for `.from()` queries. These override the
|
|
67
|
+
* corresponding client-level defaults for a single query.
|
|
68
|
+
*/
|
|
69
|
+
export type PostgrestQueryBuilderOptions = {
|
|
70
|
+
/** A custom fetch implementation for this request only. The client's `wrapFetch` and `timeout` apply to it as well. */
|
|
71
|
+
fetch?: Fetch
|
|
72
|
+
/** Override the client-level URL length limit for this request. */
|
|
73
|
+
urlLengthLimit?: number
|
|
74
|
+
/** Override the client-level retry setting for this request. */
|
|
75
|
+
retry?: boolean
|
|
76
|
+
}
|
|
77
|
+
|
|
65
78
|
export type DatabaseWithOptions<Database, Options extends ClientServerOptions> = {
|
|
66
79
|
db: Database
|
|
67
80
|
options: Options
|
package/src/version.ts
CHANGED
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
// - Debugging and support (identifying which version is running)
|
|
5
5
|
// - Telemetry and logging (version reporting in errors/analytics)
|
|
6
6
|
// - Ensuring build artifacts match the published package version
|
|
7
|
-
export const version = '2.
|
|
7
|
+
export const version = '2.119.0-canary.1'
|