@symbo.ls/fetch 3.14.658 → 3.14.660
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 +89 -9
- package/adapters/rest.js +165 -48
- package/dist/cjs/adapters/rest.js +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/esm/adapters/rest.js +1 -1
- package/dist/esm/index.js +1 -1
- package/index.js +78 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -572,6 +572,83 @@ await queryClient.prefetchQuery({
|
|
|
572
572
|
{ fetch: { from: '/users', baseUrl: 'https://api.example.com/auth', headers: { 'X-Custom': 'value' } } }
|
|
573
573
|
```
|
|
574
574
|
|
|
575
|
+
### Per-call headers
|
|
576
|
+
|
|
577
|
+
A call's `headers` merge over the adapter's configured `headers` and its token. Names match case-insensitively and the call's value wins, so one call can send its own Bearer token (for example a per-user token). A `null` value removes a configured header. `headers` can be a plain object, a `Headers` instance or an array of `[name, value]` pairs.
|
|
578
|
+
|
|
579
|
+
```js
|
|
580
|
+
const db = await el.getDB()
|
|
581
|
+
await db.select({ from: '/me', headers: { Authorization: `Bearer ${userToken}` } })
|
|
582
|
+
await db.select({ from: '/public/feed', headers: { Authorization: null } }) // no token on this call
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
### `responseType`
|
|
586
|
+
|
|
587
|
+
`responseType` sets how the REST adapter reads the response body. It works on `select`, `rpc`, `insert`, `update`, `upsert` and `delete`, and on the declarative `fetch` options.
|
|
588
|
+
|
|
589
|
+
| Value | `data` on success |
|
|
590
|
+
|-------|-------------------|
|
|
591
|
+
| `'auto'` (default) | JSON when the `content-type` contains `json`, else text |
|
|
592
|
+
| `'json'` | parsed JSON, whatever the `content-type` says (`null` for an empty body) |
|
|
593
|
+
| `'text'` | the body as a string |
|
|
594
|
+
| `'blob'` | a `Blob` — binary bytes and the content type stay intact (audio, xlsx, csv) |
|
|
595
|
+
| `'arrayBuffer'` | an `ArrayBuffer` |
|
|
596
|
+
| `'stream'` | the body `ReadableStream`, returned before the body is read (`null` when there is no body) |
|
|
597
|
+
| `'response'` | the raw `Response`, unread (use it when you need the response headers) |
|
|
598
|
+
|
|
599
|
+
A failed response keeps the `{ data, error, status }` contract for every type. The adapter reads the body (JSON by `content-type`, else text) for the message. `error` is its `message` or `error` field, else the status text. With a type other than `'auto'`, `error` falls back to `HTTP <status>` when both are empty (an HTTP/2 response has no status text). `data` is the error body. With `'response'`, `data` stays the unread `Response`, and the message comes from a copy. An unknown `responseType` throws before the request is sent.
|
|
600
|
+
|
|
601
|
+
Read a streamed (SSE) answer chunk by chunk:
|
|
602
|
+
|
|
603
|
+
```js
|
|
604
|
+
const db = await el.getDB()
|
|
605
|
+
const { data: stream, error } = await db.insert({ from: '/ask', data: { question }, responseType: 'stream' })
|
|
606
|
+
if (error) return
|
|
607
|
+
const reader = stream.pipeThrough(new TextDecoderStream()).getReader()
|
|
608
|
+
while (true) {
|
|
609
|
+
const { value, done } = await reader.read()
|
|
610
|
+
if (done) break
|
|
611
|
+
onChunk(value) // 'data: …\n\n' lines, as the server sends them
|
|
612
|
+
}
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
Download a file as a Blob:
|
|
616
|
+
|
|
617
|
+
```js
|
|
618
|
+
const { data: blob, error } = await db.select({ from: '/finops/report.xlsx', params: { month: 9 }, responseType: 'blob' })
|
|
619
|
+
if (!error) el.state.update({ reportUrl: URL.createObjectURL(blob) }) // blob.type is the server's content-type
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
In a declarative `fetch`:
|
|
623
|
+
|
|
624
|
+
```js
|
|
625
|
+
{ state: { answerAudio: null }, fetch: { from: '/voice/answer', responseType: 'blob', as: 'answerAudio' } }
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
- A `Blob`, `ArrayBuffer`, stream or `Response` goes into state only under `as`, as the value itself. Without `as`, read it in `transform` or `onFetchComplete`.
|
|
629
|
+
- A `'stream'` or `'response'` body can be read once. So these queries are never cached or deduplicated. They send the request again on window focus or reconnect only when `refetchOnWindowFocus: true` or `refetchOnReconnect: true` is set.
|
|
630
|
+
|
|
631
|
+
### Request bodies
|
|
632
|
+
|
|
633
|
+
The REST adapter sends `data` (`insert`, `update`, `upsert`, `signIn`) and `params` (`rpc`) like this:
|
|
634
|
+
|
|
635
|
+
- `FormData`, `Blob` / `File`, `ArrayBuffer`, typed arrays / `DataView`, `URLSearchParams` and `ReadableStream` go to `fetch` as they are. The adapter sets no `Content-Type` for them, and it drops a configured one. `fetch` then writes the right one: the multipart boundary, the Blob's type or the form-urlencoded type. A per-call `Content-Type` header still applies. A `ReadableStream` is sent with `duplex: 'half'`.
|
|
636
|
+
- Every other value (plain objects, arrays, strings, …) is JSON-encoded with `Content-Type: application/json`, as before.
|
|
637
|
+
|
|
638
|
+
Upload a recording as multipart form data:
|
|
639
|
+
|
|
640
|
+
```js
|
|
641
|
+
const form = new FormData()
|
|
642
|
+
form.append('audio', recording, 'voice.webm') // a Blob, e.g. from MediaRecorder
|
|
643
|
+
const { data: reply, error } = await db.insert({ from: '/voice', data: form, responseType: 'blob' })
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
In a declarative mutation, return the `FormData` from `transform`:
|
|
647
|
+
|
|
648
|
+
```js
|
|
649
|
+
{ tag: 'form', fetch: { method: 'insert', from: '/upload', on: 'submit', transform: (data, el) => new FormData(el.node) } }
|
|
650
|
+
```
|
|
651
|
+
|
|
575
652
|
## State inheritance
|
|
576
653
|
|
|
577
654
|
When `state` is a string, the element inherits that key from the parent state. Fetch uses the same string as the default `from` (table name), so declaring `state` is often enough:
|
|
@@ -664,14 +741,16 @@ const { data, error } = await db.select({ from: 'articles' })
|
|
|
664
741
|
|
|
665
742
|
## Adapter interface
|
|
666
743
|
|
|
667
|
-
All return `{ data, error }
|
|
744
|
+
All return `{ data, error }` (the REST adapter adds `status`).
|
|
668
745
|
|
|
669
746
|
```js
|
|
670
|
-
db.select({ from, select, params, limit, offset, order, single, headers, baseUrl })
|
|
671
|
-
db.insert({ from, data, select, headers, baseUrl })
|
|
672
|
-
db.update({ from, data, params, method, headers, baseUrl }) // method: 'PUT' | 'PATCH'
|
|
673
|
-
db.
|
|
674
|
-
db.
|
|
747
|
+
db.select({ from, select, params, limit, offset, order, single, headers, baseUrl, responseType })
|
|
748
|
+
db.insert({ from, data, select, headers, baseUrl, responseType })
|
|
749
|
+
db.update({ from, data, params, method, headers, baseUrl, responseType }) // method: 'PUT' | 'PATCH'
|
|
750
|
+
db.upsert({ from, data, params, method, headers, baseUrl, responseType }) // method defaults to 'PUT'
|
|
751
|
+
db.delete({ from, params, headers, baseUrl, responseType })
|
|
752
|
+
db.rpc({ from, params, headers, baseUrl, responseType })
|
|
753
|
+
// responseType (REST): 'auto' | 'json' | 'text' | 'blob' | 'arrayBuffer' | 'stream' | 'response'
|
|
675
754
|
|
|
676
755
|
// Auth (adapter-dependent — implemented by adapters that manage sessions)
|
|
677
756
|
db.getSession()
|
|
@@ -824,8 +903,8 @@ When used as a plugin, fetch hooks into the `create` lifecycle to auto-execute f
|
|
|
824
903
|
| `getPreviousPageParam` | function | — | `(firstPage, allPages) => cursor \| null` |
|
|
825
904
|
| `refetchInterval` | number/string | — | Polling interval |
|
|
826
905
|
| `refetchIntervalInBackground` | boolean | `false` | Poll when tab hidden |
|
|
827
|
-
| `refetchOnWindowFocus` | boolean | `true` | Refetch on tab focus |
|
|
828
|
-
| `refetchOnReconnect` | boolean | `true` | Refetch on online |
|
|
906
|
+
| `refetchOnWindowFocus` | boolean | `true` (`false` for `'stream'` / `'response'`) | Refetch on tab focus |
|
|
907
|
+
| `refetchOnReconnect` | boolean | `true` (`false` for `'stream'` / `'response'`) | Refetch on online |
|
|
829
908
|
| `optimistic` | any/function | — | Optimistic update data |
|
|
830
909
|
| `invalidates` | string/array/boolean | — | Cache keys to invalidate after mutation |
|
|
831
910
|
| `onMutate` | function | — | Before mutation fires |
|
|
@@ -840,6 +919,7 @@ When used as a plugin, fetch hooks into the `create` lifecycle to auto-execute f
|
|
|
840
919
|
| `limit` | number | — | Row limit |
|
|
841
920
|
| `offset` | number | — | Row offset |
|
|
842
921
|
| `order` | string/object/array | — | Sort order |
|
|
843
|
-
| `headers` | object | — | Per-request headers (REST) |
|
|
922
|
+
| `headers` | object | — | Per-request headers (REST); merged over the configured headers and the token |
|
|
844
923
|
| `baseUrl` | string | — | Per-request base URL (REST) |
|
|
924
|
+
| `responseType` | string | `'auto'` | How the body is read (REST): `auto`, `json`, `text`, `blob`, `arrayBuffer`, `stream`, `response` |
|
|
845
925
|
| `lang` | string | auto from context/state | Language override (via params) |
|
package/adapters/rest.js
CHANGED
|
@@ -14,15 +14,131 @@ const buildUrl = (base, from, params) => {
|
|
|
14
14
|
return url.toString()
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
const
|
|
18
|
-
|
|
17
|
+
const typeTag = (value) => Object.prototype.toString.call(value).slice(8, -1)
|
|
18
|
+
|
|
19
|
+
// --- Responses ---
|
|
20
|
+
//
|
|
21
|
+
// `responseType` picks how a response body is read. 'auto' is the reader this
|
|
22
|
+
// adapter always had — JSON when the content-type says so, text otherwise — and
|
|
23
|
+
// stays the default. The others return what fetch() gives: a Blob or an
|
|
24
|
+
// ArrayBuffer for binary downloads (audio, xlsx, csv), the body ReadableStream
|
|
25
|
+
// for chunk-by-chunk reads (SSE), or the Response itself. 'stream' and
|
|
26
|
+
// 'response' return WITHOUT reading the body, so each chunk reaches the caller
|
|
27
|
+
// as the server sends it instead of as one string once the stream has ended.
|
|
28
|
+
const RESPONSE_TYPES = ['auto', 'json', 'text', 'blob', 'arrayBuffer', 'stream', 'response']
|
|
29
|
+
|
|
30
|
+
const READERS = {
|
|
31
|
+
// An empty body (204, 205) is null rather than a JSON syntax error.
|
|
32
|
+
json: async (res) => {
|
|
33
|
+
const text = await res.text()
|
|
34
|
+
return text ? JSON.parse(text) : null
|
|
35
|
+
},
|
|
36
|
+
text: (res) => res.text(),
|
|
37
|
+
blob: (res) => res.blob(),
|
|
38
|
+
arrayBuffer: (res) => res.arrayBuffer(),
|
|
39
|
+
stream: (res) => res.body,
|
|
40
|
+
response: (res) => res
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const readAuto = (res) => {
|
|
19
44
|
const contentType = res.headers.get('content-type')
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
45
|
+
return contentType && contentType.includes('json') ? res.json() : res.text()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// A failed response is read for its message whatever `responseType` asked for:
|
|
49
|
+
// the caller checks `error` first, and a Blob or a stream of an error page
|
|
50
|
+
// carries no message. Unlike 'auto', a body that claims JSON but does not parse
|
|
51
|
+
// stays text instead of throwing.
|
|
52
|
+
const readErrorBody = async (res) => {
|
|
53
|
+
const text = await res.text()
|
|
54
|
+
const contentType = res.headers.get('content-type')
|
|
55
|
+
if (text && contentType && contentType.includes('json')) {
|
|
56
|
+
try { return JSON.parse(text) } catch (_) { /* not JSON after all — keep the text */ }
|
|
57
|
+
}
|
|
58
|
+
return text
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const errorMessage = (body, res) => body?.message || body?.error || res.statusText
|
|
62
|
+
|
|
63
|
+
const request = async (url, options, responseType) => {
|
|
64
|
+
const type = responseType == null ? 'auto' : responseType
|
|
65
|
+
if (!RESPONSE_TYPES.includes(type)) {
|
|
66
|
+
throw new TypeError(`@symbo.ls/fetch rest: unknown responseType "${type}" — use one of: ${RESPONSE_TYPES.join(', ')}`)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const res = await globalThis.fetch(url, options)
|
|
70
|
+
|
|
71
|
+
if (type === 'auto') {
|
|
72
|
+
const data = await readAuto(res)
|
|
73
|
+
return { data, error: res.ok ? null : errorMessage(data, res), status: res.status }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!res.ok) {
|
|
77
|
+
// 'response' reads a copy, so the caller still gets the Response unread
|
|
78
|
+
// (Retry-After and the other headers included). `HTTP <status>` keeps the
|
|
79
|
+
// error truthy when there is neither a message nor a status text — HTTP/2
|
|
80
|
+
// responses carry no status text at all.
|
|
81
|
+
const body = await readErrorBody(type === 'response' ? res.clone() : res)
|
|
82
|
+
return {
|
|
83
|
+
data: type === 'response' ? res : body,
|
|
84
|
+
error: errorMessage(body, res) || `HTTP ${res.status}`,
|
|
85
|
+
status: res.status
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return { data: await READERS[type](res), error: null, status: res.status }
|
|
24
90
|
}
|
|
25
91
|
|
|
92
|
+
// --- Request bodies ---
|
|
93
|
+
//
|
|
94
|
+
// fetch() takes these bodies as they are and derives their Content-Type from
|
|
95
|
+
// the value: the multipart boundary for FormData, `blob.type` for a Blob or a
|
|
96
|
+
// File, x-www-form-urlencoded for URLSearchParams. JSON-encoding them turned a
|
|
97
|
+
// FormData upload into the string '{}', and a forced Content-Type loses the
|
|
98
|
+
// multipart boundary. Detection reads the toStringTag, so a value from another
|
|
99
|
+
// realm (an iframe) counts too. Anything else is JSON-encoded, as before.
|
|
100
|
+
const PASS_THROUGH_TAGS = ['FormData', 'Blob', 'File', 'URLSearchParams', 'ReadableStream', 'ArrayBuffer']
|
|
101
|
+
|
|
102
|
+
const isPassThroughBody = (value) =>
|
|
103
|
+
value !== null && typeof value === 'object' &&
|
|
104
|
+
(ArrayBuffer.isView(value) || PASS_THROUGH_TAGS.includes(typeTag(value)))
|
|
105
|
+
|
|
106
|
+
// --- Headers ---
|
|
107
|
+
//
|
|
108
|
+
// Header names are case-insensitive, object keys are not: spreading
|
|
109
|
+
// `{ authorization }` over `{ Authorization }` kept BOTH keys, and fetch()
|
|
110
|
+
// joined them into one "Bearer a, Bearer b" value. Merge by lower-cased name
|
|
111
|
+
// instead — a later source wins and keeps its own spelling, and a null or
|
|
112
|
+
// undefined value removes the header. A source may be any fetch HeadersInit:
|
|
113
|
+
// a plain object, a Headers instance or an array of [name, value] pairs.
|
|
114
|
+
const headerEntries = (source) => {
|
|
115
|
+
if (Array.isArray(source)) return source
|
|
116
|
+
if (typeof source.entries === 'function') return source.entries()
|
|
117
|
+
return Object.entries(source)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const mergeHeaders = (...sources) => {
|
|
121
|
+
const merged = {}
|
|
122
|
+
const keyOf = new Map()
|
|
123
|
+
for (const source of sources) {
|
|
124
|
+
if (!source) continue
|
|
125
|
+
for (const [name, value] of headerEntries(source)) {
|
|
126
|
+
const lower = name.toLowerCase()
|
|
127
|
+
if (keyOf.has(lower)) delete merged[keyOf.get(lower)]
|
|
128
|
+
if (value === undefined || value === null) {
|
|
129
|
+
keyOf.delete(lower)
|
|
130
|
+
continue
|
|
131
|
+
}
|
|
132
|
+
keyOf.set(lower, name)
|
|
133
|
+
merged[name] = value
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return merged
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const JSON_TYPE = { 'Content-Type': 'application/json' }
|
|
140
|
+
const NO_TYPE = { 'Content-Type': undefined }
|
|
141
|
+
|
|
26
142
|
export const setup = async ({ url, headers, auth, fetchOptions }) => {
|
|
27
143
|
if (!url) throw new Error('@symbo.ls/fetch rest: url is required')
|
|
28
144
|
return restAdapter(url, headers, auth, fetchOptions)
|
|
@@ -31,16 +147,32 @@ export const setup = async ({ url, headers, auth, fetchOptions }) => {
|
|
|
31
147
|
export const restAdapter = (baseUrl, defaultHeaders = {}, authConfig, defaultFetchOptions = {}) => {
|
|
32
148
|
let token = authConfig?.token || null
|
|
33
149
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
150
|
+
// Precedence, lowest first: the configured headers, the adapter's token, the
|
|
151
|
+
// body's Content-Type, then the call's own `headers` — so one call can send
|
|
152
|
+
// its own Bearer token (a per-user token) or its own Content-Type.
|
|
153
|
+
const tokenHeader = () => token ? { Authorization: `Bearer ${token}` } : null
|
|
39
154
|
|
|
40
|
-
const
|
|
155
|
+
const getHeaders = (extra) => mergeHeaders(defaultHeaders, tokenHeader(), extra)
|
|
41
156
|
|
|
42
157
|
const getFetchOptions = (opts) => ({ ...defaultFetchOptions, ...opts })
|
|
43
158
|
|
|
159
|
+
// Options for a request that carries a body. A pass-through body gets no
|
|
160
|
+
// Content-Type from the adapter (NO_TYPE also drops a configured one), so
|
|
161
|
+
// fetch() sets the right one; an explicit per-call Content-Type still wins.
|
|
162
|
+
const withBody = (method, body, extra) => {
|
|
163
|
+
if (!isPassThroughBody(body)) {
|
|
164
|
+
return getFetchOptions({
|
|
165
|
+
method,
|
|
166
|
+
headers: mergeHeaders(defaultHeaders, tokenHeader(), JSON_TYPE, extra),
|
|
167
|
+
body: JSON.stringify(body)
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
const opts = { method, headers: mergeHeaders(defaultHeaders, tokenHeader(), NO_TYPE, extra), body }
|
|
171
|
+
// fetch() rejects a streamed request body unless it is half duplex.
|
|
172
|
+
if (typeTag(body) === 'ReadableStream') opts.duplex = 'half'
|
|
173
|
+
return getFetchOptions(opts)
|
|
174
|
+
}
|
|
175
|
+
|
|
44
176
|
const resolveUrl = (from, base) => {
|
|
45
177
|
const b = base || baseUrl
|
|
46
178
|
if (from && (from.startsWith('http://') || from.startsWith('https://'))) return from
|
|
@@ -67,11 +199,10 @@ export const restAdapter = (baseUrl, defaultHeaders = {}, authConfig, defaultFet
|
|
|
67
199
|
|
|
68
200
|
signIn: async (credentials) => {
|
|
69
201
|
if (!authConfig?.signInUrl) throw new Error('rest: auth.signInUrl not configured')
|
|
70
|
-
const result = await request(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}))
|
|
202
|
+
const result = await request(
|
|
203
|
+
resolveUrl(authConfig.signInUrl, authConfig.baseUrl),
|
|
204
|
+
withBody('POST', credentials)
|
|
205
|
+
)
|
|
75
206
|
if (result.data?.token) token = result.data.token
|
|
76
207
|
return result
|
|
77
208
|
},
|
|
@@ -87,8 +218,9 @@ export const restAdapter = (baseUrl, defaultHeaders = {}, authConfig, defaultFet
|
|
|
87
218
|
return { error: null }
|
|
88
219
|
},
|
|
89
220
|
|
|
90
|
-
// CRUD
|
|
91
|
-
|
|
221
|
+
// CRUD — every call takes `headers` (merged over the configured ones),
|
|
222
|
+
// `baseUrl` and `responseType`.
|
|
223
|
+
select: ({ from, params, select, limit, offset, order, single, headers, baseUrl: fromBase, responseType }) => {
|
|
92
224
|
const allParams = { ...params }
|
|
93
225
|
if (select) allParams.select = select
|
|
94
226
|
if (limit) allParams.limit = limit
|
|
@@ -105,32 +237,21 @@ export const restAdapter = (baseUrl, defaultHeaders = {}, authConfig, defaultFet
|
|
|
105
237
|
}
|
|
106
238
|
return request(
|
|
107
239
|
buildUrl(fromBase || baseUrl, from || '', allParams),
|
|
108
|
-
getFetchOptions({ headers: getHeaders(headers) })
|
|
240
|
+
getFetchOptions({ headers: getHeaders(headers) }),
|
|
241
|
+
responseType
|
|
109
242
|
)
|
|
110
243
|
},
|
|
111
244
|
|
|
112
|
-
rpc: ({ from, params, headers, baseUrl: fromBase }) =>
|
|
113
|
-
request(resolveUrl(`rpc/${from}`, fromBase),
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
insert: ({ from, data, headers, baseUrl: fromBase }) =>
|
|
120
|
-
request(resolveUrl(from, fromBase), getFetchOptions({
|
|
121
|
-
method: 'POST',
|
|
122
|
-
headers: getJsonHeaders(headers),
|
|
123
|
-
body: JSON.stringify(data)
|
|
124
|
-
})),
|
|
125
|
-
|
|
126
|
-
update: ({ from, data, params, method, headers, baseUrl: fromBase }) => {
|
|
245
|
+
rpc: ({ from, params, headers, baseUrl: fromBase, responseType }) =>
|
|
246
|
+
request(resolveUrl(`rpc/${from}`, fromBase), withBody('POST', params, headers), responseType),
|
|
247
|
+
|
|
248
|
+
insert: ({ from, data, headers, baseUrl: fromBase, responseType }) =>
|
|
249
|
+
request(resolveUrl(from, fromBase), withBody('POST', data, headers), responseType),
|
|
250
|
+
|
|
251
|
+
update: ({ from, data, params, method, headers, baseUrl: fromBase, responseType }) => {
|
|
127
252
|
const id = params?.id || data?.id
|
|
128
253
|
const path = id ? `${from}/${id}` : from
|
|
129
|
-
return request(resolveUrl(path, fromBase),
|
|
130
|
-
method: method || 'PATCH',
|
|
131
|
-
headers: getJsonHeaders(headers),
|
|
132
|
-
body: JSON.stringify(data)
|
|
133
|
-
}))
|
|
254
|
+
return request(resolveUrl(path, fromBase), withBody(method || 'PATCH', data, headers), responseType)
|
|
134
255
|
},
|
|
135
256
|
|
|
136
257
|
// Create-or-replace by id. PUT-by-id is the REST-idiomatic upsert (unlike
|
|
@@ -138,23 +259,19 @@ export const restAdapter = (baseUrl, defaultHeaders = {}, authConfig, defaultFet
|
|
|
138
259
|
// treat "PUT to an id that doesn't exist yet" as a create). Callers that
|
|
139
260
|
// need different upsert semantics for their backend can still pass
|
|
140
261
|
// `method` to override.
|
|
141
|
-
upsert: ({ from, data, params, method, headers, baseUrl: fromBase }) => {
|
|
262
|
+
upsert: ({ from, data, params, method, headers, baseUrl: fromBase, responseType }) => {
|
|
142
263
|
const id = params?.id || data?.id
|
|
143
264
|
const path = id ? `${from}/${id}` : from
|
|
144
|
-
return request(resolveUrl(path, fromBase),
|
|
145
|
-
method: method || 'PUT',
|
|
146
|
-
headers: getJsonHeaders(headers),
|
|
147
|
-
body: JSON.stringify(data)
|
|
148
|
-
}))
|
|
265
|
+
return request(resolveUrl(path, fromBase), withBody(method || 'PUT', data, headers), responseType)
|
|
149
266
|
},
|
|
150
267
|
|
|
151
|
-
delete: ({ from, params, headers, baseUrl: fromBase }) => {
|
|
268
|
+
delete: ({ from, params, headers, baseUrl: fromBase, responseType }) => {
|
|
152
269
|
const id = params?.id
|
|
153
270
|
const path = id ? `${from}/${id}` : from
|
|
154
271
|
return request(resolveUrl(path, fromBase), getFetchOptions({
|
|
155
272
|
method: 'DELETE',
|
|
156
273
|
headers: getHeaders(headers)
|
|
157
|
-
}))
|
|
274
|
+
}), responseType)
|
|
158
275
|
}
|
|
159
276
|
}
|
|
160
277
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var $=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var N=(t,e)=>{for(var n in e)$(t,n,{get:e[n],enumerable:!0})},_=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of B(e))!R.call(t,r)&&r!==n&&$(t,r,{get:()=>e[r],enumerable:!(o=x(e,r))||o.enumerable});return t};var H=t=>_($({},"__esModule",{value:!0}),t);var M={};N(M,{restAdapter:()=>j,setup:()=>G});module.exports=H(M);const J=(t,e,n)=>{const o=e&&!e.startsWith("/")?"/":"",r=new URL(`${t}${o}${e}`);if(n)for(const l in n){const u=n[l];u!=null&&r.searchParams.set(l,typeof u=="object"?JSON.stringify(u):u)}return r.toString()},P=t=>Object.prototype.toString.call(t).slice(8,-1),E=["auto","json","text","blob","arrayBuffer","stream","response"],m={json:async t=>{const e=await t.text();return e?JSON.parse(e):null},text:t=>t.text(),blob:t=>t.blob(),arrayBuffer:t=>t.arrayBuffer(),stream:t=>t.body,response:t=>t},I=t=>{const e=t.headers.get("content-type");return e&&e.includes("json")?t.json():t.text()},L=async t=>{const e=await t.text(),n=t.headers.get("content-type");if(e&&n&&n.includes("json"))try{return JSON.parse(e)}catch{}return e},A=(t,e)=>t?.message||t?.error||e.statusText,p=async(t,e,n)=>{const o=n??"auto";if(!E.includes(o))throw new TypeError(`@symbo.ls/fetch rest: unknown responseType "${o}" \u2014 use one of: ${E.join(", ")}`);const r=await globalThis.fetch(t,e);if(o==="auto"){const l=await I(r);return{data:l,error:r.ok?null:A(l,r),status:r.status}}if(!r.ok){const l=await L(o==="response"?r.clone():r);return{data:o==="response"?r:l,error:A(l,r)||`HTTP ${r.status}`,status:r.status}}return{data:await m[o](r),error:null,status:r.status}},W=["FormData","Blob","File","URLSearchParams","ReadableStream","ArrayBuffer"],D=t=>t!==null&&typeof t=="object"&&(ArrayBuffer.isView(t)||W.includes(P(t))),F=t=>Array.isArray(t)?t:typeof t.entries=="function"?t.entries():Object.entries(t),O=(...t)=>{const e={},n=new Map;for(const o of t)if(o)for(const[r,l]of F(o)){const u=r.toLowerCase();if(n.has(u)&&delete e[n.get(u)],l==null){n.delete(u);continue}n.set(u,r),e[r]=l}return e},Y={"Content-Type":"application/json"},q={"Content-Type":void 0},G=async({url:t,headers:e,auth:n,fetchOptions:o})=>{if(!t)throw new Error("@symbo.ls/fetch rest: url is required");return j(t,e,n,o)},j=(t,e={},n,o={})=>{let r=n?.token||null;const l=()=>r?{Authorization:`Bearer ${r}`}:null,u=s=>O(e,l(),s),w=s=>({...o,...s}),S=(s,a,i)=>{if(!D(a))return w({method:s,headers:O(e,l(),Y,i),body:JSON.stringify(a)});const c={method:s,headers:O(e,l(),q,i),body:a};return P(a)==="ReadableStream"&&(c.duplex="half"),w(c)},f=(s,a)=>{const i=a||t;if(s&&(s.startsWith("http://")||s.startsWith("https://")))return s;const c=s&&!s.startsWith("/")?"/":"";return`${i}${c}${s||""}`};return{name:"rest",setToken:s=>{r=s},getSession:async()=>{if(!n?.sessionUrl)return r?{token:r}:null;const s=await p(f(n.sessionUrl,n.baseUrl),w({headers:u()}));return s.error?null:s.data},signIn:async s=>{if(!n?.signInUrl)throw new Error("rest: auth.signInUrl not configured");const a=await p(f(n.signInUrl,n.baseUrl),S("POST",s));return a.data?.token&&(r=a.data.token),a},signOut:async()=>(n?.signOutUrl&&await p(f(n.signOutUrl,n.baseUrl),w({method:"POST",headers:u()})),r=null,{error:null}),select:({from:s,params:a,select:i,limit:c,offset:y,order:d,single:b,headers:T,baseUrl:U,responseType:k})=>{const h={...a};return i&&(h.select=i),c&&(h.limit=c),y&&(h.offset=y),b&&(h.single=!0),d&&(typeof d=="string"?h.order=d:Array.isArray(d)?h.order=d.map(g=>`${g.by}:${g.asc===!1?"desc":"asc"}`).join(","):d.by&&(h.order=`${d.by}:${d.asc===!1?"desc":"asc"}`)),p(J(U||t,s||"",h),w({headers:u(T)}),k)},rpc:({from:s,params:a,headers:i,baseUrl:c,responseType:y})=>p(f(`rpc/${s}`,c),S("POST",a,i),y),insert:({from:s,data:a,headers:i,baseUrl:c,responseType:y})=>p(f(s,c),S("POST",a,i),y),update:({from:s,data:a,params:i,method:c,headers:y,baseUrl:d,responseType:b})=>{const T=i?.id||a?.id,U=T?`${s}/${T}`:s;return p(f(U,d),S(c||"PATCH",a,y),b)},upsert:({from:s,data:a,params:i,method:c,headers:y,baseUrl:d,responseType:b})=>{const T=i?.id||a?.id,U=T?`${s}/${T}`:s;return p(f(U,d),S(c||"PUT",a,y),b)},delete:({from:s,params:a,headers:i,baseUrl:c,responseType:y})=>{const d=a?.id,b=d?`${s}/${d}`:s;return p(f(b,c),w({method:"DELETE",headers:u(i)}),y)}}};
|
package/dist/cjs/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var Nt=Object.create;var rt=Object.defineProperty;var It=Object.getOwnPropertyDescriptor;var Ot=Object.getOwnPropertyNames;var qt=Object.getPrototypeOf,Ut=Object.prototype.hasOwnProperty;var zt=(e,t)=>{for(var s in t)rt(e,s,{get:t[s],enumerable:!0})},mt=(e,t,s,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Ot(t))!Ut.call(e,o)&&o!==s&&rt(e,o,{get:()=>t[o],enumerable:!(r=It(t,o))||r.enumerable});return e};var Tt=(e,t,s)=>(s=e!=null?Nt(qt(e)):{},mt(t||!e||!e.__esModule?rt(s,"default",{value:e,enumerable:!0}):s,e)),jt=e=>mt(rt({},"__esModule",{value:!0}),e);var oe={};zt(oe,{createAdapter:()=>Yt,default:()=>ae,executeFetch:()=>wt,fetchPlugin:()=>re,initAdapterAuth:()=>ct,parseDuration:()=>W,queryClient:()=>se,registerAdapter:()=>Kt,resolveDb:()=>kt});module.exports=jt(oe);var f=require("@symbo.ls/utils");const Gt=["select","rpc","insert","update","upsert","delete","subscribe"],Qt={rest:()=>import("./adapters/rest.js"),local:()=>import("./adapters/local.js")},at=Symbol.for("@symbo.ls/fetch:CUSTOM_ADAPTERS"),Y=(()=>{if(typeof globalThis<"u"&&globalThis[at])return globalThis[at];const e={};if(typeof globalThis<"u")try{return Object.defineProperty(globalThis,at,{value:e,writable:!1,configurable:!1,enumerable:!1}),globalThis[at]}catch{}return e})(),ot=Symbol.for("@symbo.ls/fetch:PENDING_ADAPTERS"),pt=(()=>{if(typeof globalThis<"u"&&globalThis[ot])return globalThis[ot];const e={};if(typeof globalThis<"u")try{return Object.defineProperty(globalThis,ot,{value:e,writable:!1,configurable:!1,enumerable:!1}),globalThis[ot]}catch{}return e})(),xt=5e3,Wt=e=>new Promise(t=>{if(Y[e])return t(Y[e]);const s=pt[e]||=[];let r=!1;const o=()=>{r||(r=!0,t(Y[e]||null))};s.push(o),setTimeout(o,xt)}),Kt=(e,t)=>{Y[e]=t;const s=pt[e];if(s&&s.length){pt[e]=[];for(const r of s)r()}},Yt=e=>{const t={};for(const s of Gt)e[s]&&(t[s]=e[s]);return t.name=e.name||"custom",t},kt=async e=>{if(!e)return null;if(typeof e.select=="function")return e;const{adapter:t,...s}=e,r=typeof t=="string"?t:typeof e=="string"?e:null;if(!r)return null;let o=Y[r]||Qt[r];if(!o&&(o=await Wt(r),!o))throw new Error(`Unknown db adapter: "${r}". Use registerAdapter() for adapters with optional deps.`);const a=await o();if(!a||typeof a.setup!="function")throw new Error(`Adapter "${r}" loader returned a module without a setup() function. Got keys: [${Object.keys(a||{}).join(", ")}]. Likely a bundler chunk-resolution issue.`);return a.setup(s)},W=e=>{if(!e)return 0;if(typeof e=="number")return e;const t=e.match(/^(\d+)(ms|s|m|h)$/);if(!t)return 0;const s=parseInt(t[1]),r=t[2];return r==="ms"?s:r==="s"?s*1e3:r==="m"?s*6e4:r==="h"?s*36e5:0},b=new Map,U=new Map,B=new Map,Bt=(e,t,s)=>{if(e.cache?.key)return e.cache.key;const r=Vt(e.params),o=s?`${s}:`:"",a=`${e.from}:${e.method}:${o}${JSON.stringify(r||"")}`;return t?`${a}:${t}`:a},J=e=>b.get(e)||null,H=(e,t,s)=>{const r=b.get(e),o={data:t,error:s,time:Date.now(),stale:!1};b.set(e,o);const a=U.get(e);if(a)for(const i of a)(0,f.isFunction)(i)&&i(o);return o},V=e=>{if(e){const t=b.get(e);t&&(t.stale=!0);return}for(const[,t]of b)t.stale=!0},it=e=>{if(e){b.delete(e);return}b.clear()},ce=(e,t)=>(U.has(e)||U.set(e,new Set),U.get(e).add(t),()=>{const s=U.get(e);s&&(s.delete(t),s.size===0&&U.delete(e))}),_t=e=>!e&&e!==!1?{staleTime:6e4,gcTime:3e5}:e===!1?null:e===!0?{staleTime:6e4,gcTime:3e5}:typeof e=="number"?{staleTime:e,gcTime:Math.max(e*5,3e5)}:(0,f.isString)(e)?{staleTime:W(e),gcTime:3e5}:{staleTime:W(e.stale||e.staleTime)||6e4,gcTime:W(e.gc||e.gcTime||e.expire)||3e5,key:e.key};let nt=null;const Jt=()=>{nt||(nt=setInterval(()=>{const e=Date.now();for(const[t,s]of b){const r=U.get(t);!(r&&r.size>0)&&e-s.time>(s.gcTime||3e5)&&b.delete(t)}},3e4),nt.unref&&nt.unref())};Jt();const Ft=3,yt=e=>Math.min(1e3*2**e,3e4),Et=e=>{const t=e.retry;return t===!1?{count:0}:t===!0||t===void 0?{count:Ft,delay:yt}:typeof t=="number"?{count:t,delay:yt}:{count:t.count??Ft,delay:(0,f.isFunction)(t.delay)?t.delay:typeof t.delay=="number"?()=>t.delay:yt}},Dt=async(e,t)=>{const{count:s,delay:r}=t;let o;for(let a=0;a<=s;a++)try{const i=await e();if(i?.error){if(o=i.error,a<s){const c=(0,f.isFunction)(r)?r(a,o):r;await new Promise(n=>setTimeout(n,c));continue}return i}return i}catch(i){if(o=i,a<s){const c=(0,f.isFunction)(r)?r(a,i):r;await new Promise(n=>setTimeout(n,c));continue}throw i}return{data:null,error:o}},x={focus:new Set,online:new Set};let Ct=!1;const Ht=()=>{if(Ct||typeof window>"u")return;Ct=!0;const e=()=>{for(const s of x.focus)s()},t=()=>{for(const s of x.online)s()};window.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&e()}),window.addEventListener("focus",e),window.addEventListener("online",t)},Pt=(e,t)=>{const s=t.__ref;if(e===!0)return{from:s.__state||t.key,method:"select",query:!0,on:"create"};if((0,f.isString)(e))return{from:e,method:"select",query:!0,on:"create"};if((0,f.isObject)(e)){const r={...e};return r.from=r.from||s.__state||t.key,r.method=r.method||"select",r.on=r.on||"create",r.query===void 0&&(r.query=!0),r}return null},Vt=e=>(!e||(0,f.isFunction)(e),e),ft=(e,t)=>{const s=e?.state?.root||t?.state?.root;if(s?.lang)return s.lang},At=(e,t)=>{const r=(e?.state?.root||t?.state?.root)?.__fetchScope;return r?String(r):void 0},Lt=(e,t,s)=>{let r;if(!e)r=void 0;else if((0,f.isFunction)(e))r=e(t,t.state);else{r={};for(const o in e){const a=e[o];r[o]=(0,f.isFunction)(a)?a(t,t.state):a}}return r},ct=async(e,t)=>{if(!e||e.__authInitialized||(e.__authInitialized=!0,!e.getSession))return;const s=(r,o)=>{const a=t.state?.root;a?.update&&a.update({auth:{user:r,session:o,loading:!1}})};try{const r=await e.getSession();s(r?.user||null,r)}catch(r){console.warn("[fetch] Failed to restore auth session:",r.message)}e.onAuthStateChange&&e.onAuthStateChange((r,o)=>{s(o?.user||null,o)})},gt=async(e,t)=>{if((0,f.isFunction)(e.select))return e.auth!==!1&&await ct(e,t),e;if(e.__resolved)return e.auth!==!1&&await ct(e.__resolved,t),e.__resolved;if(e.__resolving)return e.__resolving;e.__resolving=kt(e);const s=await e.__resolving;return delete e.__resolving,s?(s.auth=e.auth,s.url=e.url,s.key=e.key,e.__resolved=s,t.fetch=s,e.auth!==!1&&await ct(s,t),s):null},T=(e,t,...s)=>{const r=(0,f.isFunction)(e[t])?e[t]:null;r&&r.call(e,...s,e,e.state,e.context)},C=(e,t,s,...r)=>{const o=e&&(0,f.isFunction)(e[s])?e[s]:null;o&&o.call(t,...r,t,t.state,t.context)},X=e=>{const t={},s=e.node;if(!s)return t;if(s.tagName==="FORM"){const o=new FormData(s);for(const[a,i]of o.entries())t[a]=i;return t}const r=s.querySelectorAll("input, textarea, select");for(let o=0;o<r.length;o++){const a=r[o],i=a.name||a.getAttribute("name");i&&(a.type==="checkbox"?t[i]=a.checked:a.type==="file"?t[i]=a.files:t[i]=a.value)}return t},z=(e,t,s,r={})=>{const o=s&&s.startsWith("~/"),a=o&&e.state?.root||e.state;if(a?.update)if(o){const i=s.slice(2);t&&typeof t=="object"&&!Array.isArray(t)&&i in t?a.update(t,{preventFetch:!0,...r}):a.update({[i]:t},{preventFetch:!0,...r})}else{const i=s?{[s]:t}:t;a.update(i,{preventFetch:!0,...r})}},k=(e,t)=>{const s=e?.__ref;s&&(s.__fetchStatus=t,s.__fetching=t.isFetching,s.__fetchError=t.error)},I=async(e,t,s,r={})=>{const o=s?.fetch;if(!o||!t||!t.__ref||e.enabled===!1||(0,f.isFunction)(e.enabled)&&!e.enabled(t,t.state)||e.skip===!0||(0,f.isFunction)(e.skip)&&e.skip(t,t.state))return;const a=await gt(o,s);if(!a||!t.__ref)return;const i=t.__ref,{from:c,method:n,query:_,params:v,cache:Z,transform:F,single:ut,auth:tt,fields:R,as:O,limit:K,offset:et,order:j,headers:N,baseUrl:y,page:g,cursor:m,getNextPageParam:G,getPreviousPageParam:S,infinite:P,placeholderData:q,initialData:Q,select:A,keepPreviousData:$}=e;let E=(0,f.isString)(A)?A:void 0;if(_&&(0,f.isFunction)(t.getQuery)){const d=t.getQuery(a.name||"paths");d&&(E=d.select||d.length&&d.join(",")||E)}const L=Lt(v,t,s),D=_t(Z),st=Et(e),lt=ft(t,s),bt=At(t,s),$t=lt?`:${lt}`:"",Mt=bt?`${bt}:`:"",p=D?Z?.key||`${c}:${n}:${Mt}${JSON.stringify(L||"")}${P?":infinite":""}${g?":p"+JSON.stringify(g):""}${$t}`:null;if(!i.__fetchInitialized&&p&&(i.__fetchInitialized=!0,Q!==void 0)){const d=(0,f.isFunction)(Q)?Q():Q;H(p,d,null)}if((n==="select"||n==="rpc")&&p&&D){const d=J(p);if(d&&!d.error){const l=Date.now()-d.time,h=d.stale||l>(D.staleTime||0);let u=d.data;if((0,f.isFunction)(A)&&(u=A(u,t,t.state)),F&&(u=F(u,t,t.state)),z(t,u,O),!h){k(t,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!0,error:null,status:"success",fetchStatus:"idle"});return}}else if(q!==void 0){const l=(0,f.isFunction)(q)?q(t,t.state):q;l!==void 0&&z(t,l,O)}}if(p&&B.has(p)&&!r.force){const d=B.get(p);try{const l=await Promise.race([d,new Promise((h,u)=>setTimeout(()=>u("DEDUP_TIMEOUT"),15e3))]);if(l?.data!==void 0){let h=l.data;(0,f.isFunction)(A)&&(h=A(h,t,t.state)),F&&(h=F(h,t,t.state)),z(t,h,O),T(t,"onFetchComplete",h),C(e,t,"onFetchComplete",h)}}catch{}return}const Rt=!J(p)?.data;k(t,{isFetching:!0,isLoading:Rt,isStale:!1,isSuccess:!1,error:null,status:"pending",fetchStatus:"fetching"}),T(t,"onFetchStart"),C(e,t,"onFetchStart");const M=s?.analyze?.emitNetwork,dt=M?typeof performance<"u"?performance.now():Date.now():0;M&&M({phase:"start",mode:"query",from:c,method:n,cacheKey:p,lang:lt});const vt=Dt(async()=>{if(tt!==!1&&a.auth!==!1&&a.getSession){const u=await a.getSession();if(tt===!0&&!u){const w={message:"Not authenticated"};return k(t,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:w,status:"error",fetchStatus:"idle"}),T(t,"onFetchError",w),C(e,t,"onFetchError",w),{data:null,error:w}}}const d=a[n];if(!(0,f.isFunction)(d))return{data:null,error:{message:`Method "${n}" not found on adapter`}};const l={from:c,select:E,params:L,single:ut,limit:K,offset:et,order:j,headers:N,baseUrl:y},h=ft(t,s);if(h&&(l.headers={...l.headers,"Accept-Language":h}),g!==void 0){if((0,f.isObject)(g))g.offset!==void 0&&(l.offset=g.offset),g.limit!==void 0&&(l.limit=g.limit),g.cursor!==void 0&&(l.params={...l.params,cursor:g.cursor});else if(typeof g=="number"){const u=e.pageSize||K||20;l.offset=(g-1)*u,l.limit=u}}if(m!==void 0&&(l.params={...l.params,cursor:m}),n==="insert"||n==="update"||n==="upsert"){let u;if(R===!0||e.on==="submit")u=X(t);else if((0,f.isArray)(R)){const w=X(t);u={};for(const ht of R)u[ht]=w[ht]}else t.state?.parse?u=t.state.parse():(0,f.isObject)(t.state)&&(u={...t.state});F&&(u=F(u,t,t.state)),l.data=u}if(n==="rpc"){let u=L;if(e.on==="submit"){const w=X(t);u=e.transformParams?e.transformParams(w,t,t.state):w}l.params=u}if(n==="subscribe"){const u=a.subscribe({from:c,params:L,on:e.subscribeOn},(w,ht,ne)=>{z(t,w,O),T(t,"onFetchComplete",w),C(e,t,"onFetchComplete",w)});return i.__unsubscribe=u,{data:null,error:null,subscribed:!0}}return d(l)},st);p&&B.set(p,vt);try{const d=await vt;if(d?.subscribed)return;const{data:l,error:h}=d||{};if(h){p&&H(p,null,h),k(t,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:h,status:"error",fetchStatus:"idle"}),T(t,"onFetchError",h),C(e,t,"onFetchError",h),M&&M({phase:"error",mode:"query",from:c,method:n,cacheKey:p,error:h.message||h,durationMs:(typeof performance<"u"?performance.now():Date.now())-dt});return}if(l!==void 0){if((n==="select"||n==="rpc")&&p){const w=H(p,l,null);w.gcTime=D?.gcTime||3e5}let u=l;P&&(0,f.isArray)(l)&&(i.__pages||(i.__pages=[]),r.direction==="previous"?i.__pages.unshift(l):i.__pages.push(l),u=i.__pages.flat(),G&&(i.__nextPageParam=G(l,i.__pages),i.__hasNextPage=i.__nextPageParam!=null),S&&(i.__prevPageParam=S(l,i.__pages),i.__hasPreviousPage=i.__prevPageParam!=null)),(0,f.isFunction)(A)&&(u=A(u,t,t.state)),F&&(u=F(u,t,t.state)),(!$||u!==void 0)&&z(t,u,O),k(t,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!0,error:null,status:"success",fetchStatus:"idle"}),T(t,"onFetchComplete",u),C(e,t,"onFetchComplete",u),M&&M({phase:"success",mode:"query",ok:!0,from:c,method:n,cacheKey:p,durationMs:(typeof performance<"u"?performance.now():Date.now())-dt})}}catch(d){k(t,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:d,status:"error",fetchStatus:"idle"}),T(t,"onFetchError",d),C(e,t,"onFetchError",d),M&&M({phase:"error",mode:"query",from:c,method:n,cacheKey:p,error:d.message||String(d),durationMs:(typeof performance<"u"?performance.now():Date.now())-dt})}finally{p&&B.delete(p)}},Xt=(e,t,s)=>{const r=e.on,o=t.__ref;o.__fetchListeners||(o.__fetchListeners=[]);const a=e.__runner||I;if(r==="submit"){const i=n=>{n.preventDefault(),a(e,t,s)},c=t.node;c&&(c.addEventListener("submit",i),o.__fetchListeners.push(()=>c.removeEventListener("submit",i)))}else if(r==="click"){const i=()=>a(e,t,s),c=t.node;c&&(c.addEventListener("click",i),o.__fetchListeners.push(()=>c.removeEventListener("click",i)))}else r==="stateChange"&&(o.__fetchOnStateChange=()=>a(e,t,s))},Zt=(e,t,s)=>{const r=t.__ref;r.__fetchCleanups||(r.__fetchCleanups=[]),Ht();const o=e.refetchInterval;if(o){const a=typeof o=="number"?o:W(o);if(a>0){const i=setInterval(()=>{(e.refetchIntervalInBackground||typeof document>"u"||document.visibilityState==="visible")&&I(e,t,s,{force:!0})},a);r.__fetchCleanups.push(()=>clearInterval(i))}}if(e.refetchOnWindowFocus!==!1){const a=()=>{const i=ft(t,s),c=At(t,s),n=Bt(e,i,c),_=J(n),v=_t(e.cache);(!_||_.stale||Date.now()-_.time>(v?.staleTime||0))&&I(e,t,s,{force:!0})};x.focus.add(a),r.__fetchCleanups.push(()=>x.focus.delete(a))}if(e.refetchOnReconnect!==!1){const a=()=>I(e,t,s,{force:!0});x.online.add(a),r.__fetchCleanups.push(()=>x.online.delete(a))}},te=(e,t,s)=>{if(!t.optimistic)return null;const r=e.__ref,o=t.as,a=e.state?.parse?e.state.parse():(0,f.isObject)(e.state)?{...e.state}:e.state;r.__optimisticSnapshot=a;const i=(0,f.isFunction)(t.optimistic)?t.optimistic(s,a,e):t.optimistic;return i!==void 0&&z(e,i,o),a},St=(e,t)=>{const s=e.__ref,r=s.__optimisticSnapshot;r!==void 0&&(z(e,r,t.as),delete s.__optimisticSnapshot)},ee=async(e,t,s)=>{const r=s?.fetch;if(!r)return;const o=await gt(r,s);if(!o)return;const a=t.__ref,{method:i,from:c,fields:n,transform:_,as:v,on:Z,auth:F,headers:ut,baseUrl:tt,invalidates:R,optimistic:O,onMutate:K,onSuccess:et,onError:j,onSettled:N}=e;let y;if(n===!0||Z==="submit")y=X(t);else if((0,f.isArray)(n)){const S=X(t);y={};for(const P of n)y[P]=S[P]}else t.state?.parse?y=t.state.parse():(0,f.isObject)(t.state)&&(y={...t.state});_&&(y=_(y,t,t.state)),(0,f.isFunction)(K)&&K(y,t,t.state);const g=O?te(t,e,y):null;a.__fetching=!0,k(t,{isFetching:!0,isLoading:!1,isStale:!1,isSuccess:!1,error:null,status:"pending",fetchStatus:"fetching"}),T(t,"onFetchStart"),C(e,t,"onFetchStart");const m=s?.analyze?.emitNetwork,G=m?typeof performance<"u"?performance.now():Date.now():0;m&&m({phase:"start",mode:"mutation",from:c,method:i});try{if(F!==!1&&o.auth!==!1&&o.getSession){const L=await o.getSession();if(F===!0&&!L){g!==void 0&&St(t,e);const D={message:"Not authenticated"};T(t,"onFetchError",D),C(e,t,"onFetchError",D);return}}const S=o[i];if(!(0,f.isFunction)(S))return;const P={from:c,data:y,headers:ut,baseUrl:tt};e.params&&(P.params=Lt(e.params,t,s));const q=ft(t,s);q&&(P.headers={...P.headers,"Accept-Language":q});const Q=Et(e),A=await Dt(()=>S(P),Q),{data:$,error:E}=A||{};if(E){g!==void 0&&St(t,e),k(t,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:E,status:"error",fetchStatus:"idle"}),T(t,"onFetchError",E),(0,f.isFunction)(j)&&j(E,y,t),(0,f.isFunction)(N)&&N(null,E,y,t),m&&m({phase:"error",mode:"mutation",from:c,method:i,error:E.message||String(E),durationMs:(typeof performance<"u"?performance.now():Date.now())-G});return}if(delete a.__optimisticSnapshot,$!==void 0){const L=v?{[v]:$}:$;t.state?.update&&t.state.update(L,{preventFetch:!0})}if(k(t,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!0,error:null,status:"success",fetchStatus:"idle"}),T(t,"onFetchComplete",$),C(e,t,"onFetchComplete",$),(0,f.isFunction)(et)&&et($,y,t),(0,f.isFunction)(N)&&N($,null,y,t),m&&m({phase:"success",mode:"mutation",ok:!0,from:c,method:i,durationMs:(typeof performance<"u"?performance.now():Date.now())-G}),R){const L=(0,f.isArray)(R)?R:[R];for(const D of L)if(D===!0||D==="*")for(const[st]of b)st.startsWith(c+":")&&V(st);else V(D)}}catch(S){g!==void 0&&St(t,e),k(t,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:S,status:"error",fetchStatus:"idle"}),T(t,"onFetchError",S),C(e,t,"onFetchError",S),(0,f.isFunction)(j)&&j(S,y,t),(0,f.isFunction)(N)&&N(null,S,y,t),m&&m({phase:"error",mode:"mutation",from:c,method:i,error:S.message||String(S),durationMs:(typeof performance<"u"?performance.now():Date.now())-G})}finally{a.__fetching=!1}},wt=(e,t,s,r)=>{if(!e||!r?.fetch)return;const a=(0,f.exec)(e,t);if(!a)return;const i=(0,f.isArray)(a)?a.map(n=>Pt((0,f.exec)(n,t),t)).filter(Boolean):[Pt(a,t)].filter(Boolean);for(const n of i){const _=n.method==="insert"||n.method==="update"||n.method==="upsert"||n.method==="delete",v=_?ee:I;n.on==="create"?v(n,t,r):Promise.resolve().then(()=>{Xt({...n,__runner:v},t,r)}),!_&&n.on==="create"&&(n.refetchInterval||n.refetchOnWindowFocus!==!1||n.refetchOnReconnect!==!1)&&Zt(n,t,r)}const c=t.__ref;c.refetch=n=>{for(const _ of i)I(_,t,r,{force:!0,...n})},c.fetchNextPage=()=>{const n=i[0];if(!n||!n.infinite)return;const _=c.__nextPageParam;if(_==null)return;const v={...n,cursor:_};I(v,t,r,{direction:"next",force:!0})},c.fetchPreviousPage=()=>{const n=i[0];if(!n||!n.infinite)return;const _=c.__prevPageParam;if(_==null)return;const v={...n,cursor:_};I(v,t,r,{direction:"previous",force:!0})}},se={invalidateQueries:e=>{if(!e){V();return}if((0,f.isString)(e))for(const[t]of b)(t.startsWith(e)||t.includes(e))&&V(t);else if((0,f.isArray)(e)){const t=e.join(":");for(const[s]of b)s.includes(t)&&V(s)}},removeQueries:e=>{if(!e){it();return}if((0,f.isString)(e))for(const[t]of b)(t.startsWith(e)||t.includes(e))&&it(t)},getQueryData:e=>J(e)?.data??void 0,setQueryData:(e,t)=>{const s=J(e),r=(0,f.isFunction)(t)?t(s?.data):t;H(e,r,null)},prefetchQuery:async(e,t)=>{const s=t?.fetch;if(!s)return;const r=await gt(s,t);if(!r)return;const o=e.cache?.key||`${e.from}:${e.method||"select"}:${JSON.stringify(e.params||"")}`,a=r[e.method||"select"];if(!(0,f.isFunction)(a))return;const i=await a({from:e.from,params:e.params,limit:e.limit,offset:e.offset,order:e.order,single:e.single});if(i?.data!==void 0&&!i?.error){const c=H(o,i.data,null);c.gcTime=_t(e.cache)?.gcTime||3e5}return i},getCache:()=>b,clear:()=>it(),dropNonLang:e=>{if(!e)return;const t=`:${e}`;for(const[s]of b)s.match(/:([a-z]{2,3})$/i)&&(s.endsWith(t)||it(s))}},re={name:"fetch",create(e){const t=e.fetch;t&&(e.parent||B.clear(),wt(t,e,e.state,e.context))}};var ae=wt;
|
|
1
|
+
"use strict";var zt=Object.create;var at=Object.defineProperty;var jt=Object.getOwnPropertyDescriptor;var Bt=Object.getOwnPropertyNames;var Gt=Object.getPrototypeOf,Qt=Object.prototype.hasOwnProperty;var Wt=(t,e)=>{for(var s in e)at(t,s,{get:e[s],enumerable:!0})},Ct=(t,e,s,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Bt(e))!Qt.call(t,o)&&o!==s&&at(t,o,{get:()=>e[o],enumerable:!(r=jt(e,o))||r.enumerable});return t};var Pt=(t,e,s)=>(s=t!=null?zt(Gt(t)):{},Ct(e||!t||!t.__esModule?at(s,"default",{value:t,enumerable:!0}):s,t)),Yt=t=>Ct(at({},"__esModule",{value:!0}),t);var le={};Wt(le,{createAdapter:()=>Xt,default:()=>ue,executeFetch:()=>Dt,fetchPlugin:()=>ce,initAdapterAuth:()=>ht,parseDuration:()=>Y,queryClient:()=>fe,registerAdapter:()=>Ht,resolveDb:()=>Mt});module.exports=Yt(le);var f=require("@symbo.ls/utils");const xt=["select","rpc","insert","update","upsert","delete","subscribe"],Kt={rest:()=>import("./adapters/rest.js"),local:()=>import("./adapters/local.js")},ft=Symbol.for("@symbo.ls/fetch:CUSTOM_ADAPTERS"),V=(()=>{if(typeof globalThis<"u"&&globalThis[ft])return globalThis[ft];const t={};if(typeof globalThis<"u")try{return Object.defineProperty(globalThis,ft,{value:t,writable:!1,configurable:!1,enumerable:!1}),globalThis[ft]}catch{}return t})(),ct=Symbol.for("@symbo.ls/fetch:PENDING_ADAPTERS"),St=(()=>{if(typeof globalThis<"u"&&globalThis[ct])return globalThis[ct];const t={};if(typeof globalThis<"u")try{return Object.defineProperty(globalThis,ct,{value:t,writable:!1,configurable:!1,enumerable:!1}),globalThis[ct]}catch{}return t})(),Jt=5e3,Vt=t=>new Promise(e=>{if(V[t])return e(V[t]);const s=St[t]||=[];let r=!1;const o=()=>{r||(r=!0,e(V[t]||null))};s.push(o),setTimeout(o,Jt)}),Ht=(t,e)=>{V[t]=e;const s=St[t];if(s&&s.length){St[t]=[];for(const r of s)r()}},Xt=t=>{const e={};for(const s of xt)t[s]&&(e[s]=t[s]);return e.name=t.name||"custom",e},Mt=async t=>{if(!t)return null;if(typeof t.select=="function")return t;const{adapter:e,...s}=t,r=typeof e=="string"?e:typeof t=="string"?t:null;if(!r)return null;let o=V[r]||Kt[r];if(!o&&(o=await Vt(r),!o))throw new Error(`Unknown db adapter: "${r}". Use registerAdapter() for adapters with optional deps.`);const n=await o();if(!n||typeof n.setup!="function")throw new Error(`Adapter "${r}" loader returned a module without a setup() function. Got keys: [${Object.keys(n||{}).join(", ")}]. Likely a bundler chunk-resolution issue.`);return n.setup(s)},Y=t=>{if(!t)return 0;if(typeof t=="number")return t;const e=t.match(/^(\d+)(ms|s|m|h)$/);if(!e)return 0;const s=parseInt(e[1]),r=e[2];return r==="ms"?s:r==="s"?s*1e3:r==="m"?s*6e4:r==="h"?s*36e5:0},T=new Map,U=new Map,Q=new Map,Zt=(t,e,s)=>{if(t.cache?.key)return t.cache.key;const r=se(t.params),o=s?`${s}:`:"",n=`${t.from}:${t.method}:${o}${JSON.stringify(r||"")}`;return e?`${n}:${e}`:n},H=t=>T.get(t)||null,X=(t,e,s)=>{const r=T.get(t),o={data:e,error:s,time:Date.now(),stale:!1};T.set(t,o);const n=U.get(t);if(n)for(const a of n)(0,f.isFunction)(a)&&a(o);return o},Z=t=>{if(t){const e=T.get(t);e&&(e.stale=!0);return}for(const[,e]of T)e.stale=!0},ut=t=>{if(t){T.delete(t);return}T.clear()},_e=(t,e)=>(U.has(t)||U.set(t,new Set),U.get(t).add(e),()=>{const s=U.get(t);s&&(s.delete(e),s.size===0&&U.delete(t))}),bt=t=>!t&&t!==!1?{staleTime:6e4,gcTime:3e5}:t===!1?null:t===!0?{staleTime:6e4,gcTime:3e5}:typeof t=="number"?{staleTime:t,gcTime:Math.max(t*5,3e5)}:(0,f.isString)(t)?{staleTime:Y(t),gcTime:3e5}:{staleTime:Y(t.stale||t.staleTime)||6e4,gcTime:Y(t.gc||t.gcTime||t.expire)||3e5,key:t.key};let lt=null;const te=()=>{lt||(lt=setInterval(()=>{const t=Date.now();for(const[e,s]of T){const r=U.get(e);!(r&&r.size>0)&&t-s.time>(s.gcTime||3e5)&&T.delete(e)}},3e4),lt.unref&<.unref())};te();const At=3,wt=t=>Math.min(1e3*2**t,3e4),Lt=t=>{const e=t.retry;return e===!1?{count:0}:e===!0||e===void 0?{count:At,delay:wt}:typeof e=="number"?{count:e,delay:wt}:{count:e.count??At,delay:(0,f.isFunction)(e.delay)?e.delay:typeof e.delay=="number"?()=>e.delay:wt}},Ot=async(t,e)=>{const{count:s,delay:r}=e;let o;for(let n=0;n<=s;n++)try{const a=await t();if(a?.error){if(o=a.error,n<s){const u=(0,f.isFunction)(r)?r(n,o):r;await new Promise(i=>setTimeout(i,u));continue}return a}return a}catch(a){if(o=a,n<s){const u=(0,f.isFunction)(r)?r(n,a):r;await new Promise(i=>setTimeout(i,u));continue}throw a}return{data:null,error:o}},W={focus:new Set,online:new Set};let Rt=!1;const ee=()=>{if(Rt||typeof window>"u")return;Rt=!0;const t=()=>{for(const s of W.focus)s()},e=()=>{for(const s of W.online)s()};window.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&t()}),window.addEventListener("focus",t),window.addEventListener("online",e)},kt=(t,e)=>{const s=e.__ref;if(t===!0)return{from:s.__state||e.key,method:"select",query:!0,on:"create"};if((0,f.isString)(t))return{from:t,method:"select",query:!0,on:"create"};if((0,f.isObject)(t)){const r={...t};return r.from=r.from||s.__state||e.key,r.method=r.method||"select",r.on=r.on||"create",r.query===void 0&&(r.query=!0),r}return null},se=t=>(!t||(0,f.isFunction)(t),t),dt=(t,e)=>{const s=t?.state?.root||e?.state?.root;if(s?.lang)return s.lang},Tt=(t,e)=>{const r=(t?.state?.root||e?.state?.root)?.__fetchScope;return r?String(r):void 0},$t=(t,e,s)=>{let r;if(!t)r=void 0;else if((0,f.isFunction)(t))r=t(e,e.state);else{r={};for(const o in t){const n=t[o];r[o]=(0,f.isFunction)(n)?n(e,e.state):n}}return r},ht=async(t,e)=>{if(!t||t.__authInitialized||(t.__authInitialized=!0,!t.getSession))return;const s=(r,o)=>{const n=e.state?.root;n?.update&&n.update({auth:{user:r,session:o,loading:!1}})};try{const r=await t.getSession();s(r?.user||null,r)}catch(r){console.warn("[fetch] Failed to restore auth session:",r.message)}t.onAuthStateChange&&t.onAuthStateChange((r,o)=>{s(o?.user||null,o)})},mt=async(t,e)=>{if((0,f.isFunction)(t.select))return t.auth!==!1&&await ht(t,e),t;if(t.__resolved)return t.auth!==!1&&await ht(t.__resolved,e),t.__resolved;if(t.__resolving)return t.__resolving;t.__resolving=Mt(t);const s=await t.__resolving;return delete t.__resolving,s?(s.auth=t.auth,s.url=t.url,s.key=t.key,t.__resolved=s,e.fetch=s,t.auth!==!1&&await ht(s,e),s):null},E=(t,e,...s)=>{const r=(0,f.isFunction)(t[e])?t[e]:null;r&&r.call(t,...s,t,t.state,t.context)},A=(t,e,s,...r)=>{const o=t&&(0,f.isFunction)(t[s])?t[s]:null;o&&o.call(e,...r,e,e.state,e.context)},tt=t=>{const e={},s=t.node;if(!s)return e;if(s.tagName==="FORM"){const o=new FormData(s);for(const[n,a]of o.entries())e[n]=a;return e}const r=s.querySelectorAll("input, textarea, select");for(let o=0;o<r.length;o++){const n=r[o],a=n.name||n.getAttribute("name");a&&(n.type==="checkbox"?e[a]=n.checked:n.type==="file"?e[a]=n.files:e[a]=n.value)}return e},vt=t=>t.responseType==="stream"||t.responseType==="response",re=["Blob","File","ArrayBuffer","ReadableStream","Response"],Ft=t=>t!==null&&typeof t=="object"&&(ArrayBuffer.isView(t)||re.includes(Object.prototype.toString.call(t).slice(8,-1))),q=(t,e,s,r={})=>{if(!s&&Ft(e))return;const o=s&&s.startsWith("~/"),n=o&&t.state?.root||t.state;if(n?.update)if(o){const a=s.slice(2);e&&typeof e=="object"&&!Array.isArray(e)&&!Ft(e)&&a in e?n.update(e,{preventFetch:!0,...r}):n.update({[a]:e},{preventFetch:!0,...r})}else{const a=s?{[s]:e}:e;n.update(a,{preventFetch:!0,...r})}},L=(t,e)=>{const s=t?.__ref;s&&(s.__fetchStatus=e,s.__fetching=e.isFetching,s.__fetchError=e.error)},N=async(t,e,s,r={})=>{const o=s?.fetch;if(!o||!e||!e.__ref)return;const n=e.__ref,a=Tt(e,s);(!n.__fetchScopeOwner||n.__fetchScopeOwner.scope!==a)&&(n.__fetchScopeOwner={scope:a});const u=n.__fetchScopeOwner,i=()=>e.__ref===n&&n.__fetchScopeOwner===u&&Tt(e,s)===a;if(t.enabled===!1||(0,f.isFunction)(t.enabled)&&!t.enabled(e,e.state)||t.skip===!0||(0,f.isFunction)(t.skip)&&t.skip(e,e.state))return;const h=await mt(o,s);if(!h||!i())return;const{from:g,method:S,query:R,params:x,cache:et,transform:D,single:z,auth:st,fields:j,as:k,limit:I,offset:$,order:b,headers:K,baseUrl:C,responseType:B,page:p,cursor:P,getNextPageParam:J,getPreviousPageParam:rt,infinite:nt,placeholderData:v,initialData:F,select:m,keepPreviousData:M}=t;let G=(0,f.isString)(m)?m:void 0;if(R&&(0,f.isFunction)(e.getQuery)){const d=e.getQuery(h.name||"paths");d&&(G=d.select||d.length&&d.join(",")||G)}const ot=$t(x,e,s),it=vt(t)?null:bt(et),Nt=Lt(t),pt=dt(e,s),It=pt?`:${pt}`:"",Ut=a?`${a}:`:"",_=it?et?.key||`${g}:${S}:${Ut}${JSON.stringify(ot||"")}${nt?":infinite":""}${p?":p"+JSON.stringify(p):""}${It}`:null;if(!n.__fetchInitialized&&_&&(n.__fetchInitialized=!0,F!==void 0)){const d=(0,f.isFunction)(F)?F():F;X(_,d,null)}if((S==="select"||S==="rpc")&&_&&it){const d=H(_);if(d&&!d.error){const l=Date.now()-d.time,y=d.stale||l>(it.staleTime||0);let c=d.data;if((0,f.isFunction)(m)&&(c=m(c,e,e.state)),D&&(c=D(c,e,e.state)),!i())return;if(q(e,c,k),!y){L(e,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!0,error:null,status:"success",fetchStatus:"idle"});return}}else if(v!==void 0){const l=(0,f.isFunction)(v)?v(e,e.state):v;l!==void 0&&q(e,l,k)}}if(_&&Q.has(_)&&!r.force){const d=Q.get(_);try{const l=await Promise.race([d,new Promise((y,c)=>setTimeout(()=>c("DEDUP_TIMEOUT"),15e3))]);if(!i())return;if(l?.data!==void 0){let y=l.data;if((0,f.isFunction)(m)&&(y=m(y,e,e.state)),D&&(y=D(y,e,e.state)),!i())return;q(e,y,k),E(e,"onFetchComplete",y),A(t,e,"onFetchComplete",y)}}catch{if(!i())return}return}const qt=!H(_)?.data;L(e,{isFetching:!0,isLoading:qt,isStale:!1,isSuccess:!1,error:null,status:"pending",fetchStatus:"fetching"}),E(e,"onFetchStart"),A(t,e,"onFetchStart");const O=s?.analyze?.emitNetwork,_t=O?typeof performance<"u"?performance.now():Date.now():0;O&&O({phase:"start",mode:"query",from:g,method:S,cacheKey:_,lang:pt});const yt=Ot(async()=>{if(!i())return;if(st!==!1&&h.auth!==!1&&h.getSession){const c=await h.getSession();if(!i())return;if(st===!0&&!c){const w={message:"Not authenticated"};return L(e,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:w,status:"error",fetchStatus:"idle"}),E(e,"onFetchError",w),A(t,e,"onFetchError",w),{data:null,error:w}}}const d=h[S];if(!(0,f.isFunction)(d))return{data:null,error:{message:`Method "${S}" not found on adapter`}};const l={from:g,select:G,params:ot,single:z,limit:I,offset:$,order:b,headers:K,baseUrl:C};B!==void 0&&(l.responseType=B);const y=dt(e,s);if(y&&(l.headers={...l.headers,"Accept-Language":y}),p!==void 0){if((0,f.isObject)(p))p.offset!==void 0&&(l.offset=p.offset),p.limit!==void 0&&(l.limit=p.limit),p.cursor!==void 0&&(l.params={...l.params,cursor:p.cursor});else if(typeof p=="number"){const c=t.pageSize||I||20;l.offset=(p-1)*c,l.limit=c}}if(P!==void 0&&(l.params={...l.params,cursor:P}),S==="insert"||S==="update"||S==="upsert"){let c;if(j===!0||t.on==="submit")c=tt(e);else if((0,f.isArray)(j)){const w=tt(e);c={};for(const gt of j)c[gt]=w[gt]}else e.state?.parse?c=e.state.parse():(0,f.isObject)(e.state)&&(c={...e.state});D&&(c=D(c,e,e.state)),l.data=c}if(S==="rpc"){let c=ot;if(t.on==="submit"){const w=tt(e);c=t.transformParams?t.transformParams(w,e,e.state):w}l.params=c}if(S==="subscribe"){const c=h.subscribe({from:g,params:ot,on:t.subscribeOn},(w,gt,he)=>{i()&&(q(e,w,k),E(e,"onFetchComplete",w),A(t,e,"onFetchComplete",w))});return i()?(n.__unsubscribe=c,{data:null,error:null,subscribed:!0}):((0,f.isFunction)(c)&&c(),{data:null,error:null,subscribed:!0})}return d(l)},Nt);_&&Q.set(_,yt);try{const d=await yt;if(!i()||d?.subscribed)return;const{data:l,error:y}=d||{};if(y){_&&X(_,null,y),L(e,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:y,status:"error",fetchStatus:"idle"}),E(e,"onFetchError",y),A(t,e,"onFetchError",y),O&&O({phase:"error",mode:"query",from:g,method:S,cacheKey:_,error:y.message||y,durationMs:(typeof performance<"u"?performance.now():Date.now())-_t});return}if(l!==void 0){if((S==="select"||S==="rpc")&&_){const w=X(_,l,null);w.gcTime=it?.gcTime||3e5}let c=l;if(nt&&(0,f.isArray)(l)&&(n.__pages||(n.__pages=[]),r.direction==="previous"?n.__pages.unshift(l):n.__pages.push(l),c=n.__pages.flat(),J&&(n.__nextPageParam=J(l,n.__pages),n.__hasNextPage=n.__nextPageParam!=null),rt&&(n.__prevPageParam=rt(l,n.__pages),n.__hasPreviousPage=n.__prevPageParam!=null)),(0,f.isFunction)(m)&&(c=m(c,e,e.state)),D&&(c=D(c,e,e.state)),!i())return;(!M||c!==void 0)&&q(e,c,k),L(e,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!0,error:null,status:"success",fetchStatus:"idle"}),E(e,"onFetchComplete",c),A(t,e,"onFetchComplete",c),O&&O({phase:"success",mode:"query",ok:!0,from:g,method:S,cacheKey:_,durationMs:(typeof performance<"u"?performance.now():Date.now())-_t})}}catch(d){if(!i())return;L(e,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:d,status:"error",fetchStatus:"idle"}),E(e,"onFetchError",d),A(t,e,"onFetchError",d),O&&O({phase:"error",mode:"query",from:g,method:S,cacheKey:_,error:d.message||String(d),durationMs:(typeof performance<"u"?performance.now():Date.now())-_t})}finally{_&&Q.get(_)===yt&&Q.delete(_)}},ne=(t,e,s)=>{const r=t.on,o=e.__ref;o.__fetchListeners||(o.__fetchListeners=[]);const n=t.__runner||N;if(r==="submit"){const a=i=>{i.preventDefault(),n(t,e,s)},u=e.node;u&&(u.addEventListener("submit",a),o.__fetchListeners.push(()=>u.removeEventListener("submit",a)))}else if(r==="click"){const a=()=>n(t,e,s),u=e.node;u&&(u.addEventListener("click",a),o.__fetchListeners.push(()=>u.removeEventListener("click",a)))}else r==="stateChange"&&(o.__fetchOnStateChange=()=>n(t,e,s))},oe=(t,e,s)=>{const r=e.__ref;r.__fetchCleanups||(r.__fetchCleanups=[]),ee();const o=t.refetchInterval;if(o){const i=typeof o=="number"?o:Y(o);if(i>0){const h=setInterval(()=>{(t.refetchIntervalInBackground||typeof document>"u"||document.visibilityState==="visible")&&N(t,e,s,{force:!0})},i);r.__fetchCleanups.push(()=>clearInterval(h))}}const n=vt(t),a=t.refetchOnWindowFocus===void 0?!n:t.refetchOnWindowFocus!==!1,u=t.refetchOnReconnect===void 0?!n:t.refetchOnReconnect!==!1;if(a){const i=()=>{const h=dt(e,s),g=Tt(e,s),S=Zt(t,h,g),R=H(S),x=bt(t.cache);(!R||R.stale||Date.now()-R.time>(x?.staleTime||0))&&N(t,e,s,{force:!0})};W.focus.add(i),r.__fetchCleanups.push(()=>W.focus.delete(i))}if(u){const i=()=>N(t,e,s,{force:!0});W.online.add(i),r.__fetchCleanups.push(()=>W.online.delete(i))}},ie=(t,e,s)=>{if(!e.optimistic)return null;const r=t.__ref,o=e.as,n=t.state?.parse?t.state.parse():(0,f.isObject)(t.state)?{...t.state}:t.state;r.__optimisticSnapshot=n;const a=(0,f.isFunction)(e.optimistic)?e.optimistic(s,n,t):e.optimistic;return a!==void 0&&q(t,a,o),n},Et=(t,e)=>{const s=t.__ref,r=s.__optimisticSnapshot;r!==void 0&&(q(t,r,e.as),delete s.__optimisticSnapshot)},ae=async(t,e,s)=>{const r=s?.fetch;if(!r)return;const o=await mt(r,s);if(!o)return;const n=e.__ref,{method:a,from:u,fields:i,transform:h,as:g,on:S,auth:R,headers:x,baseUrl:et,responseType:D,invalidates:z,optimistic:st,onMutate:j,onSuccess:k,onError:I,onSettled:$}=t;let b;if(i===!0||S==="submit")b=tt(e);else if((0,f.isArray)(i)){const p=tt(e);b={};for(const P of i)b[P]=p[P]}else e.state?.parse?b=e.state.parse():(0,f.isObject)(e.state)&&(b={...e.state});h&&(b=h(b,e,e.state)),(0,f.isFunction)(j)&&j(b,e,e.state);const K=st?ie(e,t,b):null;n.__fetching=!0,L(e,{isFetching:!0,isLoading:!1,isStale:!1,isSuccess:!1,error:null,status:"pending",fetchStatus:"fetching"}),E(e,"onFetchStart"),A(t,e,"onFetchStart");const C=s?.analyze?.emitNetwork,B=C?typeof performance<"u"?performance.now():Date.now():0;C&&C({phase:"start",mode:"mutation",from:u,method:a});try{if(R!==!1&&o.auth!==!1&&o.getSession){const m=await o.getSession();if(R===!0&&!m){K!==void 0&&Et(e,t);const M={message:"Not authenticated"};E(e,"onFetchError",M),A(t,e,"onFetchError",M);return}}const p=o[a];if(!(0,f.isFunction)(p))return;const P={from:u,data:b,headers:x,baseUrl:et};D!==void 0&&(P.responseType=D),t.params&&(P.params=$t(t.params,e,s));const J=dt(e,s);J&&(P.headers={...P.headers,"Accept-Language":J});const rt=Lt(t),nt=await Ot(()=>p(P),rt),{data:v,error:F}=nt||{};if(F){K!==void 0&&Et(e,t),L(e,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:F,status:"error",fetchStatus:"idle"}),E(e,"onFetchError",F),(0,f.isFunction)(I)&&I(F,b,e),(0,f.isFunction)($)&&$(null,F,b,e),C&&C({phase:"error",mode:"mutation",from:u,method:a,error:F.message||String(F),durationMs:(typeof performance<"u"?performance.now():Date.now())-B});return}if(delete n.__optimisticSnapshot,v!==void 0&&(g||!Ft(v))){const m=g?{[g]:v}:v;e.state?.update&&e.state.update(m,{preventFetch:!0})}if(L(e,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!0,error:null,status:"success",fetchStatus:"idle"}),E(e,"onFetchComplete",v),A(t,e,"onFetchComplete",v),(0,f.isFunction)(k)&&k(v,b,e),(0,f.isFunction)($)&&$(v,null,b,e),C&&C({phase:"success",mode:"mutation",ok:!0,from:u,method:a,durationMs:(typeof performance<"u"?performance.now():Date.now())-B}),z){const m=(0,f.isArray)(z)?z:[z];for(const M of m)if(M===!0||M==="*")for(const[G]of T)G.startsWith(u+":")&&Z(G);else Z(M)}}catch(p){K!==void 0&&Et(e,t),L(e,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:p,status:"error",fetchStatus:"idle"}),E(e,"onFetchError",p),A(t,e,"onFetchError",p),(0,f.isFunction)(I)&&I(p,b,e),(0,f.isFunction)($)&&$(null,p,b,e),C&&C({phase:"error",mode:"mutation",from:u,method:a,error:p.message||String(p),durationMs:(typeof performance<"u"?performance.now():Date.now())-B})}finally{n.__fetching=!1}},Dt=(t,e,s,r)=>{if(!t||!r?.fetch)return;const n=(0,f.exec)(t,e);if(!n)return;const a=(0,f.isArray)(n)?n.map(i=>kt((0,f.exec)(i,e),e)).filter(Boolean):[kt(n,e)].filter(Boolean);for(const i of a){const h=i.method==="insert"||i.method==="update"||i.method==="upsert"||i.method==="delete",g=h?ae:N;i.on==="create"?g(i,e,r):Promise.resolve().then(()=>{ne({...i,__runner:g},e,r)}),!h&&i.on==="create"&&(i.refetchInterval||i.refetchOnWindowFocus!==!1||i.refetchOnReconnect!==!1)&&oe(i,e,r)}const u=e.__ref;u.refetch=i=>{for(const h of a)N(h,e,r,{force:!0,...i})},u.fetchNextPage=()=>{const i=a[0];if(!i||!i.infinite)return;const h=u.__nextPageParam;if(h==null)return;const g={...i,cursor:h};N(g,e,r,{direction:"next",force:!0})},u.fetchPreviousPage=()=>{const i=a[0];if(!i||!i.infinite)return;const h=u.__prevPageParam;if(h==null)return;const g={...i,cursor:h};N(g,e,r,{direction:"previous",force:!0})}},fe={invalidateQueries:t=>{if(!t){Z();return}if((0,f.isString)(t))for(const[e]of T)(e.startsWith(t)||e.includes(t))&&Z(e);else if((0,f.isArray)(t)){const e=t.join(":");for(const[s]of T)s.includes(e)&&Z(s)}},removeQueries:t=>{if(!t){ut();return}if((0,f.isString)(t))for(const[e]of T)(e.startsWith(t)||e.includes(t))&&ut(e)},getQueryData:t=>H(t)?.data??void 0,setQueryData:(t,e)=>{const s=H(t),r=(0,f.isFunction)(e)?e(s?.data):e;X(t,r,null)},prefetchQuery:async(t,e)=>{const s=e?.fetch;if(!s)return;const r=await mt(s,e);if(!r)return;const o=t.cache?.key||`${t.from}:${t.method||"select"}:${JSON.stringify(t.params||"")}`,n=r[t.method||"select"];if(!(0,f.isFunction)(n))return;const a={from:t.from,params:t.params,limit:t.limit,offset:t.offset,order:t.order,single:t.single,headers:t.headers,baseUrl:t.baseUrl};t.responseType!==void 0&&(a.responseType=t.responseType);const u=await n(a);if(u?.data!==void 0&&!u?.error&&!vt(t)){const i=X(o,u.data,null);i.gcTime=bt(t.cache)?.gcTime||3e5}return u},getCache:()=>T,clear:()=>ut(),dropNonLang:t=>{if(!t)return;const e=`:${t}`;for(const[s]of T)s.match(/:([a-z]{2,3})$/i)&&(s.endsWith(e)||ut(s))}},ce={name:"fetch",create(t){const e=t.fetch;e&&(t.parent||Q.clear(),Dt(e,t,t.state,t.context))}};var ue=Dt;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const j=(t,r,n)=>{const c=r&&!r.startsWith("/")?"/":"",s=new URL(`${t}${c}${r}`);if(n)for(const l in n){const u=n[l];u!=null&&s.searchParams.set(l,typeof u=="object"?JSON.stringify(u):u)}return s.toString()},g=t=>Object.prototype.toString.call(t).slice(8,-1),P=["auto","json","text","blob","arrayBuffer","stream","response"],k={json:async t=>{const r=await t.text();return r?JSON.parse(r):null},text:t=>t.text(),blob:t=>t.blob(),arrayBuffer:t=>t.arrayBuffer(),stream:t=>t.body,response:t=>t},x=t=>{const r=t.headers.get("content-type");return r&&r.includes("json")?t.json():t.text()},B=async t=>{const r=await t.text(),n=t.headers.get("content-type");if(r&&n&&n.includes("json"))try{return JSON.parse(r)}catch{}return r},E=(t,r)=>t?.message||t?.error||r.statusText,p=async(t,r,n)=>{const c=n??"auto";if(!P.includes(c))throw new TypeError(`@symbo.ls/fetch rest: unknown responseType "${c}" \u2014 use one of: ${P.join(", ")}`);const s=await globalThis.fetch(t,r);if(c==="auto"){const l=await x(s);return{data:l,error:s.ok?null:E(l,s),status:s.status}}if(!s.ok){const l=await B(c==="response"?s.clone():s);return{data:c==="response"?s:l,error:E(l,s)||`HTTP ${s.status}`,status:s.status}}return{data:await k[c](s),error:null,status:s.status}},R=["FormData","Blob","File","URLSearchParams","ReadableStream","ArrayBuffer"],N=t=>t!==null&&typeof t=="object"&&(ArrayBuffer.isView(t)||R.includes(g(t))),_=t=>Array.isArray(t)?t:typeof t.entries=="function"?t.entries():Object.entries(t),$=(...t)=>{const r={},n=new Map;for(const c of t)if(c)for(const[s,l]of _(c)){const u=s.toLowerCase();if(n.has(u)&&delete r[n.get(u)],l==null){n.delete(u);continue}n.set(u,s),r[s]=l}return r},H={"Content-Type":"application/json"},J={"Content-Type":void 0},L=async({url:t,headers:r,auth:n,fetchOptions:c})=>{if(!t)throw new Error("@symbo.ls/fetch rest: url is required");return m(t,r,n,c)},m=(t,r={},n,c={})=>{let s=n?.token||null;const l=()=>s?{Authorization:`Bearer ${s}`}:null,u=e=>$(r,l(),e),w=e=>({...c,...e}),S=(e,a,o)=>{if(!N(a))return w({method:e,headers:$(r,l(),H,o),body:JSON.stringify(a)});const i={method:e,headers:$(r,l(),J,o),body:a};return g(a)==="ReadableStream"&&(i.duplex="half"),w(i)},f=(e,a)=>{const o=a||t;if(e&&(e.startsWith("http://")||e.startsWith("https://")))return e;const i=e&&!e.startsWith("/")?"/":"";return`${o}${i}${e||""}`};return{name:"rest",setToken:e=>{s=e},getSession:async()=>{if(!n?.sessionUrl)return s?{token:s}:null;const e=await p(f(n.sessionUrl,n.baseUrl),w({headers:u()}));return e.error?null:e.data},signIn:async e=>{if(!n?.signInUrl)throw new Error("rest: auth.signInUrl not configured");const a=await p(f(n.signInUrl,n.baseUrl),S("POST",e));return a.data?.token&&(s=a.data.token),a},signOut:async()=>(n?.signOutUrl&&await p(f(n.signOutUrl,n.baseUrl),w({method:"POST",headers:u()})),s=null,{error:null}),select:({from:e,params:a,select:o,limit:i,offset:y,order:d,single:b,headers:T,baseUrl:U,responseType:A})=>{const h={...a};return o&&(h.select=o),i&&(h.limit=i),y&&(h.offset=y),b&&(h.single=!0),d&&(typeof d=="string"?h.order=d:Array.isArray(d)?h.order=d.map(O=>`${O.by}:${O.asc===!1?"desc":"asc"}`).join(","):d.by&&(h.order=`${d.by}:${d.asc===!1?"desc":"asc"}`)),p(j(U||t,e||"",h),w({headers:u(T)}),A)},rpc:({from:e,params:a,headers:o,baseUrl:i,responseType:y})=>p(f(`rpc/${e}`,i),S("POST",a,o),y),insert:({from:e,data:a,headers:o,baseUrl:i,responseType:y})=>p(f(e,i),S("POST",a,o),y),update:({from:e,data:a,params:o,method:i,headers:y,baseUrl:d,responseType:b})=>{const T=o?.id||a?.id,U=T?`${e}/${T}`:e;return p(f(U,d),S(i||"PATCH",a,y),b)},upsert:({from:e,data:a,params:o,method:i,headers:y,baseUrl:d,responseType:b})=>{const T=o?.id||a?.id,U=T?`${e}/${T}`:e;return p(f(U,d),S(i||"PUT",a,y),b)},delete:({from:e,params:a,headers:o,baseUrl:i,responseType:y})=>{const d=a?.id,b=d?`${e}/${d}`:e;return p(f(b,i),w({method:"DELETE",headers:u(o)}),y)}}};export{m as restAdapter,L as setup};
|
package/dist/esm/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isArray as x,isFunction as l,isObject as Y,isString as B,exec as Tt}from"@symbo.ls/utils";const Nt=["select","rpc","insert","update","upsert","delete","subscribe"],It={rest:()=>import("./adapters/rest.js"),local:()=>import("./adapters/local.js")},it=Symbol.for("@symbo.ls/fetch:CUSTOM_ADAPTERS"),J=(()=>{if(typeof globalThis<"u"&&globalThis[it])return globalThis[it];const e={};if(typeof globalThis<"u")try{return Object.defineProperty(globalThis,it,{value:e,writable:!1,configurable:!1,enumerable:!1}),globalThis[it]}catch{}return e})(),nt=Symbol.for("@symbo.ls/fetch:PENDING_ADAPTERS"),_t=(()=>{if(typeof globalThis<"u"&&globalThis[nt])return globalThis[nt];const e={};if(typeof globalThis<"u")try{return Object.defineProperty(globalThis,nt,{value:e,writable:!1,configurable:!1,enumerable:!1}),globalThis[nt]}catch{}return e})(),Ot=5e3,qt=e=>new Promise(t=>{if(J[e])return t(J[e]);const s=_t[e]||=[];let r=!1;const i=()=>{r||(r=!0,t(J[e]||null))};s.push(i),setTimeout(i,Ot)}),Vt=(e,t)=>{J[e]=t;const s=_t[e];if(s&&s.length){_t[e]=[];for(const r of s)r()}},Xt=e=>{const t={};for(const s of Nt)e[s]&&(t[s]=e[s]);return t.name=e.name||"custom",t},Ut=async e=>{if(!e)return null;if(typeof e.select=="function")return e;const{adapter:t,...s}=e,r=typeof t=="string"?t:typeof e=="string"?e:null;if(!r)return null;let i=J[r]||It[r];if(!i&&(i=await qt(r),!i))throw new Error(`Unknown db adapter: "${r}". Use registerAdapter() for adapters with optional deps.`);const a=await i();if(!a||typeof a.setup!="function")throw new Error(`Adapter "${r}" loader returned a module without a setup() function. Got keys: [${Object.keys(a||{}).join(", ")}]. Likely a bundler chunk-resolution issue.`);return a.setup(s)},H=e=>{if(!e)return 0;if(typeof e=="number")return e;const t=e.match(/^(\d+)(ms|s|m|h)$/);if(!t)return 0;const s=parseInt(t[1]),r=t[2];return r==="ms"?s:r==="s"?s*1e3:r==="m"?s*6e4:r==="h"?s*36e5:0},b=new Map,U=new Map,V=new Map,zt=(e,t,s)=>{if(e.cache?.key)return e.cache.key;const r=Qt(e.params),i=s?`${s}:`:"",a=`${e.from}:${e.method}:${i}${JSON.stringify(r||"")}`;return t?`${a}:${t}`:a},X=e=>b.get(e)||null,Z=(e,t,s)=>{const r=b.get(e),i={data:t,error:s,time:Date.now(),stale:!1};b.set(e,i);const a=U.get(e);if(a)for(const o of a)l(o)&&o(i);return i},tt=e=>{if(e){const t=b.get(e);t&&(t.stale=!0);return}for(const[,t]of b)t.stale=!0},ft=e=>{if(e){b.delete(e);return}b.clear()},Zt=(e,t)=>(U.has(e)||U.set(e,new Set),U.get(e).add(t),()=>{const s=U.get(e);s&&(s.delete(t),s.size===0&&U.delete(e))}),yt=e=>!e&&e!==!1?{staleTime:6e4,gcTime:3e5}:e===!1?null:e===!0?{staleTime:6e4,gcTime:3e5}:typeof e=="number"?{staleTime:e,gcTime:Math.max(e*5,3e5)}:B(e)?{staleTime:H(e),gcTime:3e5}:{staleTime:H(e.stale||e.staleTime)||6e4,gcTime:H(e.gc||e.gcTime||e.expire)||3e5,key:e.key};let ct=null;const jt=()=>{ct||(ct=setInterval(()=>{const e=Date.now();for(const[t,s]of b){const r=U.get(t);!(r&&r.size>0)&&e-s.time>(s.gcTime||3e5)&&b.delete(t)}},3e4),ct.unref&&ct.unref())};jt();const Ft=3,gt=e=>Math.min(1e3*2**e,3e4),Et=e=>{const t=e.retry;return t===!1?{count:0}:t===!0||t===void 0?{count:Ft,delay:gt}:typeof t=="number"?{count:t,delay:gt}:{count:t.count??Ft,delay:l(t.delay)?t.delay:typeof t.delay=="number"?()=>t.delay:gt}},Dt=async(e,t)=>{const{count:s,delay:r}=t;let i;for(let a=0;a<=s;a++)try{const o=await e();if(o?.error){if(i=o.error,a<s){const f=l(r)?r(a,i):r;await new Promise(n=>setTimeout(n,f));continue}return o}return o}catch(o){if(i=o,a<s){const f=l(r)?r(a,o):r;await new Promise(n=>setTimeout(n,f));continue}throw o}return{data:null,error:i}},W={focus:new Set,online:new Set};let Ct=!1;const Gt=()=>{if(Ct||typeof window>"u")return;Ct=!0;const e=()=>{for(const s of W.focus)s()},t=()=>{for(const s of W.online)s()};window.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&e()}),window.addEventListener("focus",e),window.addEventListener("online",t)},Pt=(e,t)=>{const s=t.__ref;if(e===!0)return{from:s.__state||t.key,method:"select",query:!0,on:"create"};if(B(e))return{from:e,method:"select",query:!0,on:"create"};if(Y(e)){const r={...e};return r.from=r.from||s.__state||t.key,r.method=r.method||"select",r.on=r.on||"create",r.query===void 0&&(r.query=!0),r}return null},Qt=e=>(!e||l(e),e),ut=(e,t)=>{const s=e?.state?.root||t?.state?.root;if(s?.lang)return s.lang},At=(e,t)=>{const r=(e?.state?.root||t?.state?.root)?.__fetchScope;return r?String(r):void 0},Lt=(e,t,s)=>{let r;if(!e)r=void 0;else if(l(e))r=e(t,t.state);else{r={};for(const i in e){const a=e[i];r[i]=l(a)?a(t,t.state):a}}return r},St=async(e,t)=>{if(!e||e.__authInitialized||(e.__authInitialized=!0,!e.getSession))return;const s=(r,i)=>{const a=t.state?.root;a?.update&&a.update({auth:{user:r,session:i,loading:!1}})};try{const r=await e.getSession();s(r?.user||null,r)}catch(r){console.warn("[fetch] Failed to restore auth session:",r.message)}e.onAuthStateChange&&e.onAuthStateChange((r,i)=>{s(i?.user||null,i)})},wt=async(e,t)=>{if(l(e.select))return e.auth!==!1&&await St(e,t),e;if(e.__resolved)return e.auth!==!1&&await St(e.__resolved,t),e.__resolved;if(e.__resolving)return e.__resolving;e.__resolving=Ut(e);const s=await e.__resolving;return delete e.__resolving,s?(s.auth=e.auth,s.url=e.url,s.key=e.key,e.__resolved=s,t.fetch=s,e.auth!==!1&&await St(s,t),s):null},T=(e,t,...s)=>{const r=l(e[t])?e[t]:null;r&&r.call(e,...s,e,e.state,e.context)},C=(e,t,s,...r)=>{const i=e&&l(e[s])?e[s]:null;i&&i.call(t,...r,t,t.state,t.context)},et=e=>{const t={},s=e.node;if(!s)return t;if(s.tagName==="FORM"){const i=new FormData(s);for(const[a,o]of i.entries())t[a]=o;return t}const r=s.querySelectorAll("input, textarea, select");for(let i=0;i<r.length;i++){const a=r[i],o=a.name||a.getAttribute("name");o&&(a.type==="checkbox"?t[o]=a.checked:a.type==="file"?t[o]=a.files:t[o]=a.value)}return t},z=(e,t,s,r={})=>{const i=s&&s.startsWith("~/"),a=i&&e.state?.root||e.state;if(a?.update)if(i){const o=s.slice(2);t&&typeof t=="object"&&!Array.isArray(t)&&o in t?a.update(t,{preventFetch:!0,...r}):a.update({[o]:t},{preventFetch:!0,...r})}else{const o=s?{[s]:t}:t;a.update(o,{preventFetch:!0,...r})}},k=(e,t)=>{const s=e?.__ref;s&&(s.__fetchStatus=t,s.__fetching=t.isFetching,s.__fetchError=t.error)},I=async(e,t,s,r={})=>{const i=s?.fetch;if(!i||!t||!t.__ref||e.enabled===!1||l(e.enabled)&&!e.enabled(t,t.state)||e.skip===!0||l(e.skip)&&e.skip(t,t.state))return;const a=await wt(i,s);if(!a||!t.__ref)return;const o=t.__ref,{from:f,method:n,query:_,params:v,cache:st,transform:F,single:lt,auth:rt,fields:R,as:O,limit:K,offset:at,order:j,headers:N,baseUrl:y,page:g,cursor:m,getNextPageParam:G,getPreviousPageParam:S,infinite:P,placeholderData:q,initialData:Q,select:A,keepPreviousData:$}=e;let E=B(A)?A:void 0;if(_&&l(t.getQuery)){const d=t.getQuery(a.name||"paths");d&&(E=d.select||d.length&&d.join(",")||E)}const L=Lt(v,t,s),D=yt(st),ot=Et(e),dt=ut(t,s),vt=At(t,s),$t=dt?`:${dt}`:"",Mt=vt?`${vt}:`:"",p=D?st?.key||`${f}:${n}:${Mt}${JSON.stringify(L||"")}${P?":infinite":""}${g?":p"+JSON.stringify(g):""}${$t}`:null;if(!o.__fetchInitialized&&p&&(o.__fetchInitialized=!0,Q!==void 0)){const d=l(Q)?Q():Q;Z(p,d,null)}if((n==="select"||n==="rpc")&&p&&D){const d=X(p);if(d&&!d.error){const u=Date.now()-d.time,h=d.stale||u>(D.staleTime||0);let c=d.data;if(l(A)&&(c=A(c,t,t.state)),F&&(c=F(c,t,t.state)),z(t,c,O),!h){k(t,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!0,error:null,status:"success",fetchStatus:"idle"});return}}else if(q!==void 0){const u=l(q)?q(t,t.state):q;u!==void 0&&z(t,u,O)}}if(p&&V.has(p)&&!r.force){const d=V.get(p);try{const u=await Promise.race([d,new Promise((h,c)=>setTimeout(()=>c("DEDUP_TIMEOUT"),15e3))]);if(u?.data!==void 0){let h=u.data;l(A)&&(h=A(h,t,t.state)),F&&(h=F(h,t,t.state)),z(t,h,O),T(t,"onFetchComplete",h),C(e,t,"onFetchComplete",h)}}catch{}return}const Rt=!X(p)?.data;k(t,{isFetching:!0,isLoading:Rt,isStale:!1,isSuccess:!1,error:null,status:"pending",fetchStatus:"fetching"}),T(t,"onFetchStart"),C(e,t,"onFetchStart");const M=s?.analyze?.emitNetwork,ht=M?typeof performance<"u"?performance.now():Date.now():0;M&&M({phase:"start",mode:"query",from:f,method:n,cacheKey:p,lang:dt});const mt=Dt(async()=>{if(rt!==!1&&a.auth!==!1&&a.getSession){const c=await a.getSession();if(rt===!0&&!c){const w={message:"Not authenticated"};return k(t,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:w,status:"error",fetchStatus:"idle"}),T(t,"onFetchError",w),C(e,t,"onFetchError",w),{data:null,error:w}}}const d=a[n];if(!l(d))return{data:null,error:{message:`Method "${n}" not found on adapter`}};const u={from:f,select:E,params:L,single:lt,limit:K,offset:at,order:j,headers:N,baseUrl:y},h=ut(t,s);if(h&&(u.headers={...u.headers,"Accept-Language":h}),g!==void 0){if(Y(g))g.offset!==void 0&&(u.offset=g.offset),g.limit!==void 0&&(u.limit=g.limit),g.cursor!==void 0&&(u.params={...u.params,cursor:g.cursor});else if(typeof g=="number"){const c=e.pageSize||K||20;u.offset=(g-1)*c,u.limit=c}}if(m!==void 0&&(u.params={...u.params,cursor:m}),n==="insert"||n==="update"||n==="upsert"){let c;if(R===!0||e.on==="submit")c=et(t);else if(x(R)){const w=et(t);c={};for(const pt of R)c[pt]=w[pt]}else t.state?.parse?c=t.state.parse():Y(t.state)&&(c={...t.state});F&&(c=F(c,t,t.state)),u.data=c}if(n==="rpc"){let c=L;if(e.on==="submit"){const w=et(t);c=e.transformParams?e.transformParams(w,t,t.state):w}u.params=c}if(n==="subscribe"){const c=a.subscribe({from:f,params:L,on:e.subscribeOn},(w,pt,Jt)=>{z(t,w,O),T(t,"onFetchComplete",w),C(e,t,"onFetchComplete",w)});return o.__unsubscribe=c,{data:null,error:null,subscribed:!0}}return d(u)},ot);p&&V.set(p,mt);try{const d=await mt;if(d?.subscribed)return;const{data:u,error:h}=d||{};if(h){p&&Z(p,null,h),k(t,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:h,status:"error",fetchStatus:"idle"}),T(t,"onFetchError",h),C(e,t,"onFetchError",h),M&&M({phase:"error",mode:"query",from:f,method:n,cacheKey:p,error:h.message||h,durationMs:(typeof performance<"u"?performance.now():Date.now())-ht});return}if(u!==void 0){if((n==="select"||n==="rpc")&&p){const w=Z(p,u,null);w.gcTime=D?.gcTime||3e5}let c=u;P&&x(u)&&(o.__pages||(o.__pages=[]),r.direction==="previous"?o.__pages.unshift(u):o.__pages.push(u),c=o.__pages.flat(),G&&(o.__nextPageParam=G(u,o.__pages),o.__hasNextPage=o.__nextPageParam!=null),S&&(o.__prevPageParam=S(u,o.__pages),o.__hasPreviousPage=o.__prevPageParam!=null)),l(A)&&(c=A(c,t,t.state)),F&&(c=F(c,t,t.state)),(!$||c!==void 0)&&z(t,c,O),k(t,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!0,error:null,status:"success",fetchStatus:"idle"}),T(t,"onFetchComplete",c),C(e,t,"onFetchComplete",c),M&&M({phase:"success",mode:"query",ok:!0,from:f,method:n,cacheKey:p,durationMs:(typeof performance<"u"?performance.now():Date.now())-ht})}}catch(d){k(t,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:d,status:"error",fetchStatus:"idle"}),T(t,"onFetchError",d),C(e,t,"onFetchError",d),M&&M({phase:"error",mode:"query",from:f,method:n,cacheKey:p,error:d.message||String(d),durationMs:(typeof performance<"u"?performance.now():Date.now())-ht})}finally{p&&V.delete(p)}},xt=(e,t,s)=>{const r=e.on,i=t.__ref;i.__fetchListeners||(i.__fetchListeners=[]);const a=e.__runner||I;if(r==="submit"){const o=n=>{n.preventDefault(),a(e,t,s)},f=t.node;f&&(f.addEventListener("submit",o),i.__fetchListeners.push(()=>f.removeEventListener("submit",o)))}else if(r==="click"){const o=()=>a(e,t,s),f=t.node;f&&(f.addEventListener("click",o),i.__fetchListeners.push(()=>f.removeEventListener("click",o)))}else r==="stateChange"&&(i.__fetchOnStateChange=()=>a(e,t,s))},Wt=(e,t,s)=>{const r=t.__ref;r.__fetchCleanups||(r.__fetchCleanups=[]),Gt();const i=e.refetchInterval;if(i){const a=typeof i=="number"?i:H(i);if(a>0){const o=setInterval(()=>{(e.refetchIntervalInBackground||typeof document>"u"||document.visibilityState==="visible")&&I(e,t,s,{force:!0})},a);r.__fetchCleanups.push(()=>clearInterval(o))}}if(e.refetchOnWindowFocus!==!1){const a=()=>{const o=ut(t,s),f=At(t,s),n=zt(e,o,f),_=X(n),v=yt(e.cache);(!_||_.stale||Date.now()-_.time>(v?.staleTime||0))&&I(e,t,s,{force:!0})};W.focus.add(a),r.__fetchCleanups.push(()=>W.focus.delete(a))}if(e.refetchOnReconnect!==!1){const a=()=>I(e,t,s,{force:!0});W.online.add(a),r.__fetchCleanups.push(()=>W.online.delete(a))}},Kt=(e,t,s)=>{if(!t.optimistic)return null;const r=e.__ref,i=t.as,a=e.state?.parse?e.state.parse():Y(e.state)?{...e.state}:e.state;r.__optimisticSnapshot=a;const o=l(t.optimistic)?t.optimistic(s,a,e):t.optimistic;return o!==void 0&&z(e,o,i),a},bt=(e,t)=>{const s=e.__ref,r=s.__optimisticSnapshot;r!==void 0&&(z(e,r,t.as),delete s.__optimisticSnapshot)},Yt=async(e,t,s)=>{const r=s?.fetch;if(!r)return;const i=await wt(r,s);if(!i)return;const a=t.__ref,{method:o,from:f,fields:n,transform:_,as:v,on:st,auth:F,headers:lt,baseUrl:rt,invalidates:R,optimistic:O,onMutate:K,onSuccess:at,onError:j,onSettled:N}=e;let y;if(n===!0||st==="submit")y=et(t);else if(x(n)){const S=et(t);y={};for(const P of n)y[P]=S[P]}else t.state?.parse?y=t.state.parse():Y(t.state)&&(y={...t.state});_&&(y=_(y,t,t.state)),l(K)&&K(y,t,t.state);const g=O?Kt(t,e,y):null;a.__fetching=!0,k(t,{isFetching:!0,isLoading:!1,isStale:!1,isSuccess:!1,error:null,status:"pending",fetchStatus:"fetching"}),T(t,"onFetchStart"),C(e,t,"onFetchStart");const m=s?.analyze?.emitNetwork,G=m?typeof performance<"u"?performance.now():Date.now():0;m&&m({phase:"start",mode:"mutation",from:f,method:o});try{if(F!==!1&&i.auth!==!1&&i.getSession){const L=await i.getSession();if(F===!0&&!L){g!==void 0&&bt(t,e);const D={message:"Not authenticated"};T(t,"onFetchError",D),C(e,t,"onFetchError",D);return}}const S=i[o];if(!l(S))return;const P={from:f,data:y,headers:lt,baseUrl:rt};e.params&&(P.params=Lt(e.params,t,s));const q=ut(t,s);q&&(P.headers={...P.headers,"Accept-Language":q});const Q=Et(e),A=await Dt(()=>S(P),Q),{data:$,error:E}=A||{};if(E){g!==void 0&&bt(t,e),k(t,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:E,status:"error",fetchStatus:"idle"}),T(t,"onFetchError",E),l(j)&&j(E,y,t),l(N)&&N(null,E,y,t),m&&m({phase:"error",mode:"mutation",from:f,method:o,error:E.message||String(E),durationMs:(typeof performance<"u"?performance.now():Date.now())-G});return}if(delete a.__optimisticSnapshot,$!==void 0){const L=v?{[v]:$}:$;t.state?.update&&t.state.update(L,{preventFetch:!0})}if(k(t,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!0,error:null,status:"success",fetchStatus:"idle"}),T(t,"onFetchComplete",$),C(e,t,"onFetchComplete",$),l(at)&&at($,y,t),l(N)&&N($,null,y,t),m&&m({phase:"success",mode:"mutation",ok:!0,from:f,method:o,durationMs:(typeof performance<"u"?performance.now():Date.now())-G}),R){const L=x(R)?R:[R];for(const D of L)if(D===!0||D==="*")for(const[ot]of b)ot.startsWith(f+":")&&tt(ot);else tt(D)}}catch(S){g!==void 0&&bt(t,e),k(t,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:S,status:"error",fetchStatus:"idle"}),T(t,"onFetchError",S),C(e,t,"onFetchError",S),l(j)&&j(S,y,t),l(N)&&N(null,S,y,t),m&&m({phase:"error",mode:"mutation",from:f,method:o,error:S.message||String(S),durationMs:(typeof performance<"u"?performance.now():Date.now())-G})}finally{a.__fetching=!1}},kt=(e,t,s,r)=>{if(!e||!r?.fetch)return;const a=Tt(e,t);if(!a)return;const o=x(a)?a.map(n=>Pt(Tt(n,t),t)).filter(Boolean):[Pt(a,t)].filter(Boolean);for(const n of o){const _=n.method==="insert"||n.method==="update"||n.method==="upsert"||n.method==="delete",v=_?Yt:I;n.on==="create"?v(n,t,r):Promise.resolve().then(()=>{xt({...n,__runner:v},t,r)}),!_&&n.on==="create"&&(n.refetchInterval||n.refetchOnWindowFocus!==!1||n.refetchOnReconnect!==!1)&&Wt(n,t,r)}const f=t.__ref;f.refetch=n=>{for(const _ of o)I(_,t,r,{force:!0,...n})},f.fetchNextPage=()=>{const n=o[0];if(!n||!n.infinite)return;const _=f.__nextPageParam;if(_==null)return;const v={...n,cursor:_};I(v,t,r,{direction:"next",force:!0})},f.fetchPreviousPage=()=>{const n=o[0];if(!n||!n.infinite)return;const _=f.__prevPageParam;if(_==null)return;const v={...n,cursor:_};I(v,t,r,{direction:"previous",force:!0})}},te={invalidateQueries:e=>{if(!e){tt();return}if(B(e))for(const[t]of b)(t.startsWith(e)||t.includes(e))&&tt(t);else if(x(e)){const t=e.join(":");for(const[s]of b)s.includes(t)&&tt(s)}},removeQueries:e=>{if(!e){ft();return}if(B(e))for(const[t]of b)(t.startsWith(e)||t.includes(e))&&ft(t)},getQueryData:e=>X(e)?.data??void 0,setQueryData:(e,t)=>{const s=X(e),r=l(t)?t(s?.data):t;Z(e,r,null)},prefetchQuery:async(e,t)=>{const s=t?.fetch;if(!s)return;const r=await wt(s,t);if(!r)return;const i=e.cache?.key||`${e.from}:${e.method||"select"}:${JSON.stringify(e.params||"")}`,a=r[e.method||"select"];if(!l(a))return;const o=await a({from:e.from,params:e.params,limit:e.limit,offset:e.offset,order:e.order,single:e.single});if(o?.data!==void 0&&!o?.error){const f=Z(i,o.data,null);f.gcTime=yt(e.cache)?.gcTime||3e5}return o},getCache:()=>b,clear:()=>ft(),dropNonLang:e=>{if(!e)return;const t=`:${e}`;for(const[s]of b)s.match(/:([a-z]{2,3})$/i)&&(s.endsWith(t)||ft(s))}},ee={name:"fetch",create(e){const t=e.fetch;t&&(e.parent||V.clear(),kt(t,e,e.state,e.context))}};var se=kt;export{Xt as createAdapter,se as default,kt as executeFetch,ee as fetchPlugin,St as initAdapterAuth,H as parseDuration,te as queryClient,Vt as registerAdapter,Ut as resolveDb};
|
|
1
|
+
import{isArray as Q,isFunction as l,isObject as V,isString as H,exec as Pt}from"@symbo.ls/utils";const zt=["select","rpc","insert","update","upsert","delete","subscribe"],jt={rest:()=>import("./adapters/rest.js"),local:()=>import("./adapters/local.js")},ut=Symbol.for("@symbo.ls/fetch:CUSTOM_ADAPTERS"),X=(()=>{if(typeof globalThis<"u"&&globalThis[ut])return globalThis[ut];const t={};if(typeof globalThis<"u")try{return Object.defineProperty(globalThis,ut,{value:t,writable:!1,configurable:!1,enumerable:!1}),globalThis[ut]}catch{}return t})(),lt=Symbol.for("@symbo.ls/fetch:PENDING_ADAPTERS"),bt=(()=>{if(typeof globalThis<"u"&&globalThis[lt])return globalThis[lt];const t={};if(typeof globalThis<"u")try{return Object.defineProperty(globalThis,lt,{value:t,writable:!1,configurable:!1,enumerable:!1}),globalThis[lt]}catch{}return t})(),Bt=5e3,Gt=t=>new Promise(e=>{if(X[t])return e(X[t]);const s=bt[t]||=[];let r=!1;const o=()=>{r||(r=!0,e(X[t]||null))};s.push(o),setTimeout(o,Bt)}),re=(t,e)=>{X[t]=e;const s=bt[t];if(s&&s.length){bt[t]=[];for(const r of s)r()}},ne=t=>{const e={};for(const s of zt)t[s]&&(e[s]=t[s]);return e.name=t.name||"custom",e},Qt=async t=>{if(!t)return null;if(typeof t.select=="function")return t;const{adapter:e,...s}=t,r=typeof e=="string"?e:typeof t=="string"?t:null;if(!r)return null;let o=X[r]||jt[r];if(!o&&(o=await Gt(r),!o))throw new Error(`Unknown db adapter: "${r}". Use registerAdapter() for adapters with optional deps.`);const n=await o();if(!n||typeof n.setup!="function")throw new Error(`Adapter "${r}" loader returned a module without a setup() function. Got keys: [${Object.keys(n||{}).join(", ")}]. Likely a bundler chunk-resolution issue.`);return n.setup(s)},Z=t=>{if(!t)return 0;if(typeof t=="number")return t;const e=t.match(/^(\d+)(ms|s|m|h)$/);if(!e)return 0;const s=parseInt(e[1]),r=e[2];return r==="ms"?s:r==="s"?s*1e3:r==="m"?s*6e4:r==="h"?s*36e5:0},T=new Map,U=new Map,W=new Map,Wt=(t,e,s)=>{if(t.cache?.key)return t.cache.key;const r=Kt(t.params),o=s?`${s}:`:"",n=`${t.from}:${t.method}:${o}${JSON.stringify(r||"")}`;return e?`${n}:${e}`:n},tt=t=>T.get(t)||null,et=(t,e,s)=>{const r=T.get(t),o={data:e,error:s,time:Date.now(),stale:!1};T.set(t,o);const n=U.get(t);if(n)for(const a of n)l(a)&&a(o);return o},st=t=>{if(t){const e=T.get(t);e&&(e.stale=!0);return}for(const[,e]of T)e.stale=!0},dt=t=>{if(t){T.delete(t);return}T.clear()},oe=(t,e)=>(U.has(t)||U.set(t,new Set),U.get(t).add(e),()=>{const s=U.get(t);s&&(s.delete(e),s.size===0&&U.delete(t))}),wt=t=>!t&&t!==!1?{staleTime:6e4,gcTime:3e5}:t===!1?null:t===!0?{staleTime:6e4,gcTime:3e5}:typeof t=="number"?{staleTime:t,gcTime:Math.max(t*5,3e5)}:H(t)?{staleTime:Z(t),gcTime:3e5}:{staleTime:Z(t.stale||t.staleTime)||6e4,gcTime:Z(t.gc||t.gcTime||t.expire)||3e5,key:t.key};let ht=null;const Yt=()=>{ht||(ht=setInterval(()=>{const t=Date.now();for(const[e,s]of T){const r=U.get(e);!(r&&r.size>0)&&t-s.time>(s.gcTime||3e5)&&T.delete(e)}},3e4),ht.unref&&ht.unref())};Yt();const At=3,Tt=t=>Math.min(1e3*2**t,3e4),Lt=t=>{const e=t.retry;return e===!1?{count:0}:e===!0||e===void 0?{count:At,delay:Tt}:typeof e=="number"?{count:e,delay:Tt}:{count:e.count??At,delay:l(e.delay)?e.delay:typeof e.delay=="number"?()=>e.delay:Tt}},Ot=async(t,e)=>{const{count:s,delay:r}=e;let o;for(let n=0;n<=s;n++)try{const a=await t();if(a?.error){if(o=a.error,n<s){const c=l(r)?r(n,o):r;await new Promise(i=>setTimeout(i,c));continue}return a}return a}catch(a){if(o=a,n<s){const c=l(r)?r(n,a):r;await new Promise(i=>setTimeout(i,c));continue}throw a}return{data:null,error:o}},Y={focus:new Set,online:new Set};let Rt=!1;const xt=()=>{if(Rt||typeof window>"u")return;Rt=!0;const t=()=>{for(const s of Y.focus)s()},e=()=>{for(const s of Y.online)s()};window.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&t()}),window.addEventListener("focus",t),window.addEventListener("online",e)},kt=(t,e)=>{const s=e.__ref;if(t===!0)return{from:s.__state||e.key,method:"select",query:!0,on:"create"};if(H(t))return{from:t,method:"select",query:!0,on:"create"};if(V(t)){const r={...t};return r.from=r.from||s.__state||e.key,r.method=r.method||"select",r.on=r.on||"create",r.query===void 0&&(r.query=!0),r}return null},Kt=t=>(!t||l(t),t),pt=(t,e)=>{const s=t?.state?.root||e?.state?.root;if(s?.lang)return s.lang},mt=(t,e)=>{const r=(t?.state?.root||e?.state?.root)?.__fetchScope;return r?String(r):void 0},$t=(t,e,s)=>{let r;if(!t)r=void 0;else if(l(t))r=t(e,e.state);else{r={};for(const o in t){const n=t[o];r[o]=l(n)?n(e,e.state):n}}return r},vt=async(t,e)=>{if(!t||t.__authInitialized||(t.__authInitialized=!0,!t.getSession))return;const s=(r,o)=>{const n=e.state?.root;n?.update&&n.update({auth:{user:r,session:o,loading:!1}})};try{const r=await t.getSession();s(r?.user||null,r)}catch(r){console.warn("[fetch] Failed to restore auth session:",r.message)}t.onAuthStateChange&&t.onAuthStateChange((r,o)=>{s(o?.user||null,o)})},Ft=async(t,e)=>{if(l(t.select))return t.auth!==!1&&await vt(t,e),t;if(t.__resolved)return t.auth!==!1&&await vt(t.__resolved,e),t.__resolved;if(t.__resolving)return t.__resolving;t.__resolving=Qt(t);const s=await t.__resolving;return delete t.__resolving,s?(s.auth=t.auth,s.url=t.url,s.key=t.key,t.__resolved=s,e.fetch=s,t.auth!==!1&&await vt(s,e),s):null},E=(t,e,...s)=>{const r=l(t[e])?t[e]:null;r&&r.call(t,...s,t,t.state,t.context)},A=(t,e,s,...r)=>{const o=t&&l(t[s])?t[s]:null;o&&o.call(e,...r,e,e.state,e.context)},rt=t=>{const e={},s=t.node;if(!s)return e;if(s.tagName==="FORM"){const o=new FormData(s);for(const[n,a]of o.entries())e[n]=a;return e}const r=s.querySelectorAll("input, textarea, select");for(let o=0;o<r.length;o++){const n=r[o],a=n.name||n.getAttribute("name");a&&(n.type==="checkbox"?e[a]=n.checked:n.type==="file"?e[a]=n.files:e[a]=n.value)}return e},Et=t=>t.responseType==="stream"||t.responseType==="response",Jt=["Blob","File","ArrayBuffer","ReadableStream","Response"],Dt=t=>t!==null&&typeof t=="object"&&(ArrayBuffer.isView(t)||Jt.includes(Object.prototype.toString.call(t).slice(8,-1))),q=(t,e,s,r={})=>{if(!s&&Dt(e))return;const o=s&&s.startsWith("~/"),n=o&&t.state?.root||t.state;if(n?.update)if(o){const a=s.slice(2);e&&typeof e=="object"&&!Array.isArray(e)&&!Dt(e)&&a in e?n.update(e,{preventFetch:!0,...r}):n.update({[a]:e},{preventFetch:!0,...r})}else{const a=s?{[s]:e}:e;n.update(a,{preventFetch:!0,...r})}},L=(t,e)=>{const s=t?.__ref;s&&(s.__fetchStatus=e,s.__fetching=e.isFetching,s.__fetchError=e.error)},N=async(t,e,s,r={})=>{const o=s?.fetch;if(!o||!e||!e.__ref)return;const n=e.__ref,a=mt(e,s);(!n.__fetchScopeOwner||n.__fetchScopeOwner.scope!==a)&&(n.__fetchScopeOwner={scope:a});const c=n.__fetchScopeOwner,i=()=>e.__ref===n&&n.__fetchScopeOwner===c&&mt(e,s)===a;if(t.enabled===!1||l(t.enabled)&&!t.enabled(e,e.state)||t.skip===!0||l(t.skip)&&t.skip(e,e.state))return;const h=await Ft(o,s);if(!h||!i())return;const{from:g,method:S,query:R,params:x,cache:nt,transform:D,single:z,auth:ot,fields:j,as:k,limit:I,offset:$,order:b,headers:K,baseUrl:C,responseType:B,page:p,cursor:P,getNextPageParam:J,getPreviousPageParam:it,infinite:at,placeholderData:v,initialData:F,select:m,keepPreviousData:M}=t;let G=H(m)?m:void 0;if(R&&l(e.getQuery)){const d=e.getQuery(h.name||"paths");d&&(G=d.select||d.length&&d.join(",")||G)}const ft=$t(x,e,s),ct=Et(t)?null:wt(nt),Nt=Lt(t),_t=pt(e,s),It=_t?`:${_t}`:"",Ut=a?`${a}:`:"",_=ct?nt?.key||`${g}:${S}:${Ut}${JSON.stringify(ft||"")}${at?":infinite":""}${p?":p"+JSON.stringify(p):""}${It}`:null;if(!n.__fetchInitialized&&_&&(n.__fetchInitialized=!0,F!==void 0)){const d=l(F)?F():F;et(_,d,null)}if((S==="select"||S==="rpc")&&_&&ct){const d=tt(_);if(d&&!d.error){const u=Date.now()-d.time,y=d.stale||u>(ct.staleTime||0);let f=d.data;if(l(m)&&(f=m(f,e,e.state)),D&&(f=D(f,e,e.state)),!i())return;if(q(e,f,k),!y){L(e,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!0,error:null,status:"success",fetchStatus:"idle"});return}}else if(v!==void 0){const u=l(v)?v(e,e.state):v;u!==void 0&&q(e,u,k)}}if(_&&W.has(_)&&!r.force){const d=W.get(_);try{const u=await Promise.race([d,new Promise((y,f)=>setTimeout(()=>f("DEDUP_TIMEOUT"),15e3))]);if(!i())return;if(u?.data!==void 0){let y=u.data;if(l(m)&&(y=m(y,e,e.state)),D&&(y=D(y,e,e.state)),!i())return;q(e,y,k),E(e,"onFetchComplete",y),A(t,e,"onFetchComplete",y)}}catch{if(!i())return}return}const qt=!tt(_)?.data;L(e,{isFetching:!0,isLoading:qt,isStale:!1,isSuccess:!1,error:null,status:"pending",fetchStatus:"fetching"}),E(e,"onFetchStart"),A(t,e,"onFetchStart");const O=s?.analyze?.emitNetwork,yt=O?typeof performance<"u"?performance.now():Date.now():0;O&&O({phase:"start",mode:"query",from:g,method:S,cacheKey:_,lang:_t});const gt=Ot(async()=>{if(!i())return;if(ot!==!1&&h.auth!==!1&&h.getSession){const f=await h.getSession();if(!i())return;if(ot===!0&&!f){const w={message:"Not authenticated"};return L(e,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:w,status:"error",fetchStatus:"idle"}),E(e,"onFetchError",w),A(t,e,"onFetchError",w),{data:null,error:w}}}const d=h[S];if(!l(d))return{data:null,error:{message:`Method "${S}" not found on adapter`}};const u={from:g,select:G,params:ft,single:z,limit:I,offset:$,order:b,headers:K,baseUrl:C};B!==void 0&&(u.responseType=B);const y=pt(e,s);if(y&&(u.headers={...u.headers,"Accept-Language":y}),p!==void 0){if(V(p))p.offset!==void 0&&(u.offset=p.offset),p.limit!==void 0&&(u.limit=p.limit),p.cursor!==void 0&&(u.params={...u.params,cursor:p.cursor});else if(typeof p=="number"){const f=t.pageSize||I||20;u.offset=(p-1)*f,u.limit=f}}if(P!==void 0&&(u.params={...u.params,cursor:P}),S==="insert"||S==="update"||S==="upsert"){let f;if(j===!0||t.on==="submit")f=rt(e);else if(Q(j)){const w=rt(e);f={};for(const St of j)f[St]=w[St]}else e.state?.parse?f=e.state.parse():V(e.state)&&(f={...e.state});D&&(f=D(f,e,e.state)),u.data=f}if(S==="rpc"){let f=ft;if(t.on==="submit"){const w=rt(e);f=t.transformParams?t.transformParams(w,e,e.state):w}u.params=f}if(S==="subscribe"){const f=h.subscribe({from:g,params:ft,on:t.subscribeOn},(w,St,ee)=>{i()&&(q(e,w,k),E(e,"onFetchComplete",w),A(t,e,"onFetchComplete",w))});return i()?(n.__unsubscribe=f,{data:null,error:null,subscribed:!0}):(l(f)&&f(),{data:null,error:null,subscribed:!0})}return d(u)},Nt);_&&W.set(_,gt);try{const d=await gt;if(!i()||d?.subscribed)return;const{data:u,error:y}=d||{};if(y){_&&et(_,null,y),L(e,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:y,status:"error",fetchStatus:"idle"}),E(e,"onFetchError",y),A(t,e,"onFetchError",y),O&&O({phase:"error",mode:"query",from:g,method:S,cacheKey:_,error:y.message||y,durationMs:(typeof performance<"u"?performance.now():Date.now())-yt});return}if(u!==void 0){if((S==="select"||S==="rpc")&&_){const w=et(_,u,null);w.gcTime=ct?.gcTime||3e5}let f=u;if(at&&Q(u)&&(n.__pages||(n.__pages=[]),r.direction==="previous"?n.__pages.unshift(u):n.__pages.push(u),f=n.__pages.flat(),J&&(n.__nextPageParam=J(u,n.__pages),n.__hasNextPage=n.__nextPageParam!=null),it&&(n.__prevPageParam=it(u,n.__pages),n.__hasPreviousPage=n.__prevPageParam!=null)),l(m)&&(f=m(f,e,e.state)),D&&(f=D(f,e,e.state)),!i())return;(!M||f!==void 0)&&q(e,f,k),L(e,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!0,error:null,status:"success",fetchStatus:"idle"}),E(e,"onFetchComplete",f),A(t,e,"onFetchComplete",f),O&&O({phase:"success",mode:"query",ok:!0,from:g,method:S,cacheKey:_,durationMs:(typeof performance<"u"?performance.now():Date.now())-yt})}}catch(d){if(!i())return;L(e,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:d,status:"error",fetchStatus:"idle"}),E(e,"onFetchError",d),A(t,e,"onFetchError",d),O&&O({phase:"error",mode:"query",from:g,method:S,cacheKey:_,error:d.message||String(d),durationMs:(typeof performance<"u"?performance.now():Date.now())-yt})}finally{_&&W.get(_)===gt&&W.delete(_)}},Vt=(t,e,s)=>{const r=t.on,o=e.__ref;o.__fetchListeners||(o.__fetchListeners=[]);const n=t.__runner||N;if(r==="submit"){const a=i=>{i.preventDefault(),n(t,e,s)},c=e.node;c&&(c.addEventListener("submit",a),o.__fetchListeners.push(()=>c.removeEventListener("submit",a)))}else if(r==="click"){const a=()=>n(t,e,s),c=e.node;c&&(c.addEventListener("click",a),o.__fetchListeners.push(()=>c.removeEventListener("click",a)))}else r==="stateChange"&&(o.__fetchOnStateChange=()=>n(t,e,s))},Ht=(t,e,s)=>{const r=e.__ref;r.__fetchCleanups||(r.__fetchCleanups=[]),xt();const o=t.refetchInterval;if(o){const i=typeof o=="number"?o:Z(o);if(i>0){const h=setInterval(()=>{(t.refetchIntervalInBackground||typeof document>"u"||document.visibilityState==="visible")&&N(t,e,s,{force:!0})},i);r.__fetchCleanups.push(()=>clearInterval(h))}}const n=Et(t),a=t.refetchOnWindowFocus===void 0?!n:t.refetchOnWindowFocus!==!1,c=t.refetchOnReconnect===void 0?!n:t.refetchOnReconnect!==!1;if(a){const i=()=>{const h=pt(e,s),g=mt(e,s),S=Wt(t,h,g),R=tt(S),x=wt(t.cache);(!R||R.stale||Date.now()-R.time>(x?.staleTime||0))&&N(t,e,s,{force:!0})};Y.focus.add(i),r.__fetchCleanups.push(()=>Y.focus.delete(i))}if(c){const i=()=>N(t,e,s,{force:!0});Y.online.add(i),r.__fetchCleanups.push(()=>Y.online.delete(i))}},Xt=(t,e,s)=>{if(!e.optimistic)return null;const r=t.__ref,o=e.as,n=t.state?.parse?t.state.parse():V(t.state)?{...t.state}:t.state;r.__optimisticSnapshot=n;const a=l(e.optimistic)?e.optimistic(s,n,t):e.optimistic;return a!==void 0&&q(t,a,o),n},Ct=(t,e)=>{const s=t.__ref,r=s.__optimisticSnapshot;r!==void 0&&(q(t,r,e.as),delete s.__optimisticSnapshot)},Zt=async(t,e,s)=>{const r=s?.fetch;if(!r)return;const o=await Ft(r,s);if(!o)return;const n=e.__ref,{method:a,from:c,fields:i,transform:h,as:g,on:S,auth:R,headers:x,baseUrl:nt,responseType:D,invalidates:z,optimistic:ot,onMutate:j,onSuccess:k,onError:I,onSettled:$}=t;let b;if(i===!0||S==="submit")b=rt(e);else if(Q(i)){const p=rt(e);b={};for(const P of i)b[P]=p[P]}else e.state?.parse?b=e.state.parse():V(e.state)&&(b={...e.state});h&&(b=h(b,e,e.state)),l(j)&&j(b,e,e.state);const K=ot?Xt(e,t,b):null;n.__fetching=!0,L(e,{isFetching:!0,isLoading:!1,isStale:!1,isSuccess:!1,error:null,status:"pending",fetchStatus:"fetching"}),E(e,"onFetchStart"),A(t,e,"onFetchStart");const C=s?.analyze?.emitNetwork,B=C?typeof performance<"u"?performance.now():Date.now():0;C&&C({phase:"start",mode:"mutation",from:c,method:a});try{if(R!==!1&&o.auth!==!1&&o.getSession){const m=await o.getSession();if(R===!0&&!m){K!==void 0&&Ct(e,t);const M={message:"Not authenticated"};E(e,"onFetchError",M),A(t,e,"onFetchError",M);return}}const p=o[a];if(!l(p))return;const P={from:c,data:b,headers:x,baseUrl:nt};D!==void 0&&(P.responseType=D),t.params&&(P.params=$t(t.params,e,s));const J=pt(e,s);J&&(P.headers={...P.headers,"Accept-Language":J});const it=Lt(t),at=await Ot(()=>p(P),it),{data:v,error:F}=at||{};if(F){K!==void 0&&Ct(e,t),L(e,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:F,status:"error",fetchStatus:"idle"}),E(e,"onFetchError",F),l(I)&&I(F,b,e),l($)&&$(null,F,b,e),C&&C({phase:"error",mode:"mutation",from:c,method:a,error:F.message||String(F),durationMs:(typeof performance<"u"?performance.now():Date.now())-B});return}if(delete n.__optimisticSnapshot,v!==void 0&&(g||!Dt(v))){const m=g?{[g]:v}:v;e.state?.update&&e.state.update(m,{preventFetch:!0})}if(L(e,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!0,error:null,status:"success",fetchStatus:"idle"}),E(e,"onFetchComplete",v),A(t,e,"onFetchComplete",v),l(k)&&k(v,b,e),l($)&&$(v,null,b,e),C&&C({phase:"success",mode:"mutation",ok:!0,from:c,method:a,durationMs:(typeof performance<"u"?performance.now():Date.now())-B}),z){const m=Q(z)?z:[z];for(const M of m)if(M===!0||M==="*")for(const[G]of T)G.startsWith(c+":")&&st(G);else st(M)}}catch(p){K!==void 0&&Ct(e,t),L(e,{isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:p,status:"error",fetchStatus:"idle"}),E(e,"onFetchError",p),A(t,e,"onFetchError",p),l(I)&&I(p,b,e),l($)&&$(null,p,b,e),C&&C({phase:"error",mode:"mutation",from:c,method:a,error:p.message||String(p),durationMs:(typeof performance<"u"?performance.now():Date.now())-B})}finally{n.__fetching=!1}},Mt=(t,e,s,r)=>{if(!t||!r?.fetch)return;const n=Pt(t,e);if(!n)return;const a=Q(n)?n.map(i=>kt(Pt(i,e),e)).filter(Boolean):[kt(n,e)].filter(Boolean);for(const i of a){const h=i.method==="insert"||i.method==="update"||i.method==="upsert"||i.method==="delete",g=h?Zt:N;i.on==="create"?g(i,e,r):Promise.resolve().then(()=>{Vt({...i,__runner:g},e,r)}),!h&&i.on==="create"&&(i.refetchInterval||i.refetchOnWindowFocus!==!1||i.refetchOnReconnect!==!1)&&Ht(i,e,r)}const c=e.__ref;c.refetch=i=>{for(const h of a)N(h,e,r,{force:!0,...i})},c.fetchNextPage=()=>{const i=a[0];if(!i||!i.infinite)return;const h=c.__nextPageParam;if(h==null)return;const g={...i,cursor:h};N(g,e,r,{direction:"next",force:!0})},c.fetchPreviousPage=()=>{const i=a[0];if(!i||!i.infinite)return;const h=c.__prevPageParam;if(h==null)return;const g={...i,cursor:h};N(g,e,r,{direction:"previous",force:!0})}},ie={invalidateQueries:t=>{if(!t){st();return}if(H(t))for(const[e]of T)(e.startsWith(t)||e.includes(t))&&st(e);else if(Q(t)){const e=t.join(":");for(const[s]of T)s.includes(e)&&st(s)}},removeQueries:t=>{if(!t){dt();return}if(H(t))for(const[e]of T)(e.startsWith(t)||e.includes(t))&&dt(e)},getQueryData:t=>tt(t)?.data??void 0,setQueryData:(t,e)=>{const s=tt(t),r=l(e)?e(s?.data):e;et(t,r,null)},prefetchQuery:async(t,e)=>{const s=e?.fetch;if(!s)return;const r=await Ft(s,e);if(!r)return;const o=t.cache?.key||`${t.from}:${t.method||"select"}:${JSON.stringify(t.params||"")}`,n=r[t.method||"select"];if(!l(n))return;const a={from:t.from,params:t.params,limit:t.limit,offset:t.offset,order:t.order,single:t.single,headers:t.headers,baseUrl:t.baseUrl};t.responseType!==void 0&&(a.responseType=t.responseType);const c=await n(a);if(c?.data!==void 0&&!c?.error&&!Et(t)){const i=et(o,c.data,null);i.gcTime=wt(t.cache)?.gcTime||3e5}return c},getCache:()=>T,clear:()=>dt(),dropNonLang:t=>{if(!t)return;const e=`:${t}`;for(const[s]of T)s.match(/:([a-z]{2,3})$/i)&&(s.endsWith(e)||dt(s))}},ae={name:"fetch",create(t){const e=t.fetch;e&&(t.parent||W.clear(),Mt(e,t,t.state,t.context))}};var fe=Mt;export{ne as createAdapter,fe as default,Mt as executeFetch,ae as fetchPlugin,vt as initAdapterAuth,Z as parseDuration,ie as queryClient,re as registerAdapter,Qt as resolveDb};
|
package/index.js
CHANGED
|
@@ -521,9 +521,30 @@ const collectFormData = (element) => {
|
|
|
521
521
|
return data
|
|
522
522
|
}
|
|
523
523
|
|
|
524
|
+
// --- Response kinds (REST `responseType`) ---
|
|
525
|
+
|
|
526
|
+
// 'stream' and 'response' hand back a body that can be read ONCE. A cached or
|
|
527
|
+
// dedup-shared copy would reach its second reader already locked or used, so
|
|
528
|
+
// such queries skip the cache and the in-flight dedup, and they re-request on
|
|
529
|
+
// window focus / reconnect only when the config asks for it.
|
|
530
|
+
const isSingleUse = (config) => config.responseType === 'stream' || config.responseType === 'response'
|
|
531
|
+
|
|
532
|
+
// A response body the adapter returned as-is (Blob, ArrayBuffer, typed array,
|
|
533
|
+
// ReadableStream, Response). Such a value only lands in state under `as`:
|
|
534
|
+
// merging one into state would walk its prototype's enumerable members
|
|
535
|
+
// (`size`, `getReader`, …) into state keys. Detection reads the toStringTag,
|
|
536
|
+
// so values from another realm count too.
|
|
537
|
+
const BODY_VALUE_TAGS = ['Blob', 'File', 'ArrayBuffer', 'ReadableStream', 'Response']
|
|
538
|
+
const isBodyValue = (value) =>
|
|
539
|
+
value !== null && typeof value === 'object' &&
|
|
540
|
+
(ArrayBuffer.isView(value) || BODY_VALUE_TAGS.includes(Object.prototype.toString.call(value).slice(8, -1)))
|
|
541
|
+
|
|
524
542
|
// --- State update helpers ---
|
|
525
543
|
|
|
526
544
|
const updateElementState = (element, data, stateKey, options = {}) => {
|
|
545
|
+
// Nothing to merge — `transform` / `onFetchComplete` still receive it.
|
|
546
|
+
if (!stateKey && isBodyValue(data)) return
|
|
547
|
+
|
|
527
548
|
const isRoot = stateKey && stateKey.startsWith('~/')
|
|
528
549
|
const target = isRoot ? (element.state?.root || element.state) : element.state
|
|
529
550
|
if (!target?.update) return
|
|
@@ -532,7 +553,7 @@ const updateElementState = (element, data, stateKey, options = {}) => {
|
|
|
532
553
|
const key = stateKey.slice(2)
|
|
533
554
|
// If transform returned an object containing the key itself, spread on root
|
|
534
555
|
// e.g. transform returns { transactions: [...], totalSaved: 755 } for as: '~/transactions'
|
|
535
|
-
if (data && typeof data === 'object' && !Array.isArray(data) && key in data) {
|
|
556
|
+
if (data && typeof data === 'object' && !Array.isArray(data) && !isBodyValue(data) && key in data) {
|
|
536
557
|
target.update(data, { preventFetch: true, ...options })
|
|
537
558
|
} else {
|
|
538
559
|
target.update({ [key]: data }, { preventFetch: true, ...options })
|
|
@@ -568,6 +589,19 @@ const runFetch = async (config, element, context, opts = {}) => {
|
|
|
568
589
|
// if it's gone, bail before anything else touches `element`.
|
|
569
590
|
if (!element || !element.__ref) return
|
|
570
591
|
|
|
592
|
+
// Cache keys separate tenants, but they do not own an asynchronous reply.
|
|
593
|
+
// Capture before adapter/auth awaits and keep a generation per observed
|
|
594
|
+
// scope. A -> B -> A must not revive A's older request. Queries started in
|
|
595
|
+
// the same scope share this generation, so unrelated reads stay concurrent.
|
|
596
|
+
const ref = element.__ref
|
|
597
|
+
const scope = resolveScope(element, context)
|
|
598
|
+
if (!ref.__fetchScopeOwner || ref.__fetchScopeOwner.scope !== scope) {
|
|
599
|
+
ref.__fetchScopeOwner = { scope }
|
|
600
|
+
}
|
|
601
|
+
const owner = ref.__fetchScopeOwner
|
|
602
|
+
const isCurrent = () => element.__ref === ref &&
|
|
603
|
+
ref.__fetchScopeOwner === owner && resolveScope(element, context) === scope
|
|
604
|
+
|
|
571
605
|
// enabled check
|
|
572
606
|
if (config.enabled === false) return
|
|
573
607
|
if (isFunction(config.enabled) && !config.enabled(element, element.state)) return
|
|
@@ -580,13 +614,12 @@ const runFetch = async (config, element, context, opts = {}) => {
|
|
|
580
614
|
|
|
581
615
|
// Re-check after the await — a slow adapter-resolve can outlive the
|
|
582
616
|
// element that triggered the fetch.
|
|
583
|
-
if (!
|
|
617
|
+
if (!isCurrent()) return
|
|
584
618
|
|
|
585
|
-
const ref = element.__ref
|
|
586
619
|
const {
|
|
587
620
|
from, method, query, params: rawParams, cache: cacheRaw, transform,
|
|
588
621
|
single, auth, fields, as: stateKey, limit, offset, order,
|
|
589
|
-
headers, baseUrl,
|
|
622
|
+
headers, baseUrl, responseType,
|
|
590
623
|
// Pagination
|
|
591
624
|
page, cursor, getNextPageParam, getPreviousPageParam, infinite,
|
|
592
625
|
// TanStack-style options
|
|
@@ -601,10 +634,10 @@ const runFetch = async (config, element, context, opts = {}) => {
|
|
|
601
634
|
}
|
|
602
635
|
|
|
603
636
|
const params = resolveParams(rawParams, element, context)
|
|
604
|
-
|
|
637
|
+
// No cache key for a single-use body: no cache entry, no dedup sharing.
|
|
638
|
+
const cacheConfig = isSingleUse(config) ? null : parseCacheConfig(cacheRaw)
|
|
605
639
|
const retryConfig = resolveRetryConfig(config)
|
|
606
640
|
const lang = resolveLanguage(element, context)
|
|
607
|
-
const scope = resolveScope(element, context)
|
|
608
641
|
|
|
609
642
|
// Build cache key — lang suffix lets queryClient.dropNonLang(keepLang)
|
|
610
643
|
// evict stale-language entries on setLang() without flushing the rest.
|
|
@@ -635,6 +668,7 @@ const runFetch = async (config, element, context, opts = {}) => {
|
|
|
635
668
|
let data = cached.data
|
|
636
669
|
if (isFunction(selectTransform)) data = selectTransform(data, element, element.state)
|
|
637
670
|
if (transform) data = transform(data, element, element.state)
|
|
671
|
+
if (!isCurrent()) return
|
|
638
672
|
updateElementState(element, data, stateKey)
|
|
639
673
|
if (!isStale) {
|
|
640
674
|
setFetchStatus(element, { isFetching: false, isLoading: false, isStale: false, isSuccess: true, error: null, status: 'success', fetchStatus: 'idle' })
|
|
@@ -654,15 +688,18 @@ const runFetch = async (config, element, context, opts = {}) => {
|
|
|
654
688
|
const existing = activeQueries.get(cacheKey)
|
|
655
689
|
try {
|
|
656
690
|
const result = await Promise.race([existing, new Promise((_, r) => setTimeout(() => r('DEDUP_TIMEOUT'), 15000))])
|
|
691
|
+
if (!isCurrent()) return
|
|
657
692
|
if (result?.data !== undefined) {
|
|
658
693
|
let finalData = result.data
|
|
659
694
|
if (isFunction(selectTransform)) finalData = selectTransform(finalData, element, element.state)
|
|
660
695
|
if (transform) finalData = transform(finalData, element, element.state)
|
|
696
|
+
if (!isCurrent()) return
|
|
661
697
|
updateElementState(element, finalData, stateKey)
|
|
662
698
|
triggerCallback(element, 'onFetchComplete', finalData)
|
|
663
699
|
triggerConfigCallback(config, element, 'onFetchComplete', finalData)
|
|
664
700
|
}
|
|
665
701
|
} catch (e) {
|
|
702
|
+
if (!isCurrent()) return
|
|
666
703
|
// Error handled by the original caller
|
|
667
704
|
}
|
|
668
705
|
return
|
|
@@ -687,8 +724,11 @@ const runFetch = async (config, element, context, opts = {}) => {
|
|
|
687
724
|
if (_emitNet) _emitNet({ phase: 'start', mode: 'query', from, method, cacheKey, lang })
|
|
688
725
|
|
|
689
726
|
const doFetch = async () => {
|
|
727
|
+
// withRetry can invoke this again after a scope switch or unmount.
|
|
728
|
+
if (!isCurrent()) return
|
|
690
729
|
if (auth !== false && adapter.auth !== false && adapter.getSession) {
|
|
691
730
|
const session = await adapter.getSession()
|
|
731
|
+
if (!isCurrent()) return
|
|
692
732
|
if (auth === true && !session) {
|
|
693
733
|
const err = { message: 'Not authenticated' }
|
|
694
734
|
setFetchStatus(element, { isFetching: false, isLoading: false, isStale: false, isSuccess: false, error: err, status: 'error', fetchStatus: 'idle' })
|
|
@@ -702,6 +742,7 @@ const runFetch = async (config, element, context, opts = {}) => {
|
|
|
702
742
|
if (!isFunction(fn)) return { data: null, error: { message: `Method "${method}" not found on adapter` } }
|
|
703
743
|
|
|
704
744
|
const request = { from, select, params, single, limit, offset, order, headers, baseUrl }
|
|
745
|
+
if (responseType !== undefined) request.responseType = responseType
|
|
705
746
|
|
|
706
747
|
// Inject language into request headers
|
|
707
748
|
const lang = resolveLanguage(element, context)
|
|
@@ -759,11 +800,16 @@ const runFetch = async (config, element, context, opts = {}) => {
|
|
|
759
800
|
const unsubscribe = adapter.subscribe(
|
|
760
801
|
{ from, params, on: config.subscribeOn },
|
|
761
802
|
(newData, oldData, payload) => {
|
|
803
|
+
if (!isCurrent()) return
|
|
762
804
|
updateElementState(element, newData, stateKey)
|
|
763
805
|
triggerCallback(element, 'onFetchComplete', newData)
|
|
764
806
|
triggerConfigCallback(config, element, 'onFetchComplete', newData)
|
|
765
807
|
}
|
|
766
808
|
)
|
|
809
|
+
if (!isCurrent()) {
|
|
810
|
+
if (isFunction(unsubscribe)) unsubscribe()
|
|
811
|
+
return { data: null, error: null, subscribed: true }
|
|
812
|
+
}
|
|
767
813
|
ref.__unsubscribe = unsubscribe
|
|
768
814
|
return { data: null, error: null, subscribed: true }
|
|
769
815
|
}
|
|
@@ -779,6 +825,7 @@ const runFetch = async (config, element, context, opts = {}) => {
|
|
|
779
825
|
|
|
780
826
|
try {
|
|
781
827
|
const result = await fetchPromise
|
|
828
|
+
if (!isCurrent()) return
|
|
782
829
|
if (result?.subscribed) return
|
|
783
830
|
|
|
784
831
|
const { data, error } = result || {}
|
|
@@ -828,6 +875,7 @@ const runFetch = async (config, element, context, opts = {}) => {
|
|
|
828
875
|
|
|
829
876
|
if (isFunction(selectTransform)) finalData = selectTransform(finalData, element, element.state)
|
|
830
877
|
if (transform) finalData = transform(finalData, element, element.state)
|
|
878
|
+
if (!isCurrent()) return
|
|
831
879
|
|
|
832
880
|
// keepPreviousData — don't clear state while fetching new page
|
|
833
881
|
if (!keepPreviousData || finalData !== undefined) {
|
|
@@ -843,6 +891,7 @@ const runFetch = async (config, element, context, opts = {}) => {
|
|
|
843
891
|
})
|
|
844
892
|
}
|
|
845
893
|
} catch (e) {
|
|
894
|
+
if (!isCurrent()) return
|
|
846
895
|
setFetchStatus(element, { isFetching: false, isLoading: false, isStale: false, isSuccess: false, error: e, status: 'error', fetchStatus: 'idle' })
|
|
847
896
|
triggerCallback(element, 'onFetchError', e)
|
|
848
897
|
triggerConfigCallback(config, element, 'onFetchError', e)
|
|
@@ -852,7 +901,8 @@ const runFetch = async (config, element, context, opts = {}) => {
|
|
|
852
901
|
durationMs: (typeof performance !== 'undefined' ? performance.now() : Date.now()) - __analyzeStart
|
|
853
902
|
})
|
|
854
903
|
} finally {
|
|
855
|
-
|
|
904
|
+
// A forced refetch may have replaced this key while the old request ran.
|
|
905
|
+
if (cacheKey && activeQueries.get(cacheKey) === fetchPromise) activeQueries.delete(cacheKey)
|
|
856
906
|
}
|
|
857
907
|
}
|
|
858
908
|
|
|
@@ -909,8 +959,15 @@ const bindAutoRefetch = (config, element, context) => {
|
|
|
909
959
|
}
|
|
910
960
|
}
|
|
911
961
|
|
|
962
|
+
// A single-use body has no cache entry to go stale, so without an explicit
|
|
963
|
+
// opt-in every focus / reconnect would send the request again (re-asking a
|
|
964
|
+
// streamed answer, say). Other queries keep both on by default.
|
|
965
|
+
const singleUse = isSingleUse(config)
|
|
966
|
+
const onFocusEnabled = config.refetchOnWindowFocus === undefined ? !singleUse : config.refetchOnWindowFocus !== false
|
|
967
|
+
const onReconnectEnabled = config.refetchOnReconnect === undefined ? !singleUse : config.refetchOnReconnect !== false
|
|
968
|
+
|
|
912
969
|
// refetchOnWindowFocus
|
|
913
|
-
if (
|
|
970
|
+
if (onFocusEnabled) {
|
|
914
971
|
const onFocus = () => {
|
|
915
972
|
const lang = resolveLanguage(element, context)
|
|
916
973
|
const scope = resolveScope(element, context)
|
|
@@ -926,7 +983,7 @@ const bindAutoRefetch = (config, element, context) => {
|
|
|
926
983
|
}
|
|
927
984
|
|
|
928
985
|
// refetchOnReconnect
|
|
929
|
-
if (
|
|
986
|
+
if (onReconnectEnabled) {
|
|
930
987
|
const onOnline = () => runFetch(config, element, context, { force: true })
|
|
931
988
|
globalListeners.online.add(onOnline)
|
|
932
989
|
ref.__fetchCleanups.push(() => globalListeners.online.delete(onOnline))
|
|
@@ -974,7 +1031,7 @@ const runMutation = async (config, element, context) => {
|
|
|
974
1031
|
if (!adapter) return
|
|
975
1032
|
|
|
976
1033
|
const ref = element.__ref
|
|
977
|
-
const { method, from, fields, transform, as: stateKey, on: trigger, auth, headers, baseUrl, invalidates, optimistic, onMutate, onSuccess, onError, onSettled } = config
|
|
1034
|
+
const { method, from, fields, transform, as: stateKey, on: trigger, auth, headers, baseUrl, responseType, invalidates, optimistic, onMutate, onSuccess, onError, onSettled } = config
|
|
978
1035
|
|
|
979
1036
|
// Collect mutation data
|
|
980
1037
|
let mutationData
|
|
@@ -1023,6 +1080,7 @@ const runMutation = async (config, element, context) => {
|
|
|
1023
1080
|
if (!isFunction(fn)) return
|
|
1024
1081
|
|
|
1025
1082
|
const request = { from, data: mutationData, headers, baseUrl }
|
|
1083
|
+
if (responseType !== undefined) request.responseType = responseType
|
|
1026
1084
|
if (config.params) request.params = resolveParams(config.params, element, context)
|
|
1027
1085
|
|
|
1028
1086
|
// Inject language into mutation request headers
|
|
@@ -1051,7 +1109,8 @@ const runMutation = async (config, element, context) => {
|
|
|
1051
1109
|
|
|
1052
1110
|
delete ref.__optimisticSnapshot
|
|
1053
1111
|
|
|
1054
|
-
|
|
1112
|
+
// A body value (Blob, stream, …) lands in state only under `as`.
|
|
1113
|
+
if (data !== undefined && (stateKey || !isBodyValue(data))) {
|
|
1055
1114
|
const finalData = stateKey ? { [stateKey]: data } : data
|
|
1056
1115
|
if (element.state?.update) element.state.update(finalData, { preventFetch: true })
|
|
1057
1116
|
}
|
|
@@ -1216,16 +1275,20 @@ export const queryClient = {
|
|
|
1216
1275
|
const fn = adapter[config.method || 'select']
|
|
1217
1276
|
if (!isFunction(fn)) return
|
|
1218
1277
|
|
|
1219
|
-
const
|
|
1278
|
+
const request = {
|
|
1220
1279
|
from: config.from,
|
|
1221
1280
|
params: config.params,
|
|
1222
1281
|
limit: config.limit,
|
|
1223
1282
|
offset: config.offset,
|
|
1224
1283
|
order: config.order,
|
|
1225
|
-
single: config.single
|
|
1226
|
-
|
|
1284
|
+
single: config.single,
|
|
1285
|
+
headers: config.headers,
|
|
1286
|
+
baseUrl: config.baseUrl
|
|
1287
|
+
}
|
|
1288
|
+
if (config.responseType !== undefined) request.responseType = config.responseType
|
|
1289
|
+
const result = await fn(request)
|
|
1227
1290
|
|
|
1228
|
-
if (result?.data !== undefined && !result?.error) {
|
|
1291
|
+
if (result?.data !== undefined && !result?.error && !isSingleUse(config)) {
|
|
1229
1292
|
const entry = setCacheEntry(cacheKey, result.data, null)
|
|
1230
1293
|
entry.gcTime = parseCacheConfig(config.cache)?.gcTime || 300000
|
|
1231
1294
|
}
|