@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 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.delete({ from, params, headers, baseUrl })
674
- db.rpc({ from, params, headers, baseUrl })
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 request = async (url, options) => {
18
- const res = await globalThis.fetch(url, options)
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
- const data = contentType && contentType.includes('json')
21
- ? await res.json()
22
- : await res.text()
23
- return { data, error: res.ok ? null : (data?.message || data?.error || res.statusText), status: res.status }
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
- const getHeaders = (extra) => {
35
- const h = { ...defaultHeaders, ...extra }
36
- if (token) h.Authorization = `Bearer ${token}`
37
- return h
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 getJsonHeaders = (extra) => ({ ...getHeaders(extra), 'Content-Type': 'application/json' })
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(resolveUrl(authConfig.signInUrl, authConfig.baseUrl), getFetchOptions({
71
- method: 'POST',
72
- headers: getJsonHeaders(),
73
- body: JSON.stringify(credentials)
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
- select: ({ from, params, select, limit, offset, order, single, headers, baseUrl: fromBase }) => {
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), getFetchOptions({
114
- method: 'POST',
115
- headers: getJsonHeaders(headers),
116
- body: JSON.stringify(params)
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), getFetchOptions({
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), getFetchOptions({
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 O=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var J=(a,n)=>{for(var e in n)O(a,e,{get:n[e],enumerable:!0})},N=(a,n,e,c)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of P(n))!k.call(a,r)&&r!==e&&O(a,r,{get:()=>n[r],enumerable:!(c=w(n,r))||c.enumerable});return a};var j=a=>N(O({},"__esModule",{value:!0}),a);var x={};J(x,{restAdapter:()=>S,setup:()=>E});module.exports=j(x);const A=(a,n,e)=>{const c=n&&!n.startsWith("/")?"/":"",r=new URL(`${a}${c}${n}`);if(e)for(const p in e){const d=e[p];d!=null&&r.searchParams.set(p,typeof d=="object"?JSON.stringify(d):d)}return r.toString()},y=async(a,n)=>{const e=await globalThis.fetch(a,n),c=e.headers.get("content-type"),r=c&&c.includes("json")?await e.json():await e.text();return{data:r,error:e.ok?null:r?.message||r?.error||e.statusText,status:e.status}},E=async({url:a,headers:n,auth:e,fetchOptions:c})=>{if(!a)throw new Error("@symbo.ls/fetch rest: url is required");return S(a,n,e,c)},S=(a,n={},e,c={})=>{let r=e?.token||null;const p=t=>{const s={...n,...t};return r&&(s.Authorization=`Bearer ${r}`),s},d=t=>({...p(t),"Content-Type":"application/json"}),u=t=>({...c,...t}),b=(t,s)=>{const i=s||a;if(t&&(t.startsWith("http://")||t.startsWith("https://")))return t;const o=t&&!t.startsWith("/")?"/":"";return`${i}${o}${t||""}`};return{name:"rest",setToken:t=>{r=t},getSession:async()=>{if(!e?.sessionUrl)return r?{token:r}:null;const t=await y(b(e.sessionUrl,e.baseUrl),u({headers:p()}));return t.error?null:t.data},signIn:async t=>{if(!e?.signInUrl)throw new Error("rest: auth.signInUrl not configured");const s=await y(b(e.signInUrl,e.baseUrl),u({method:"POST",headers:d(),body:JSON.stringify(t)}));return s.data?.token&&(r=s.data.token),s},signOut:async()=>(e?.signOutUrl&&await y(b(e.signOutUrl,e.baseUrl),u({method:"POST",headers:p()})),r=null,{error:null}),select:({from:t,params:s,select:i,limit:o,offset:h,order:l,single:$,headers:g,baseUrl:T})=>{const U={...s};return i&&(U.select=i),o&&(U.limit=o),h&&(U.offset=h),$&&(U.single=!0),l&&(typeof l=="string"?U.order=l:Array.isArray(l)?U.order=l.map(f=>`${f.by}:${f.asc===!1?"desc":"asc"}`).join(","):l.by&&(U.order=`${l.by}:${l.asc===!1?"desc":"asc"}`)),y(A(T||a,t||"",U),u({headers:p(g)}))},rpc:({from:t,params:s,headers:i,baseUrl:o})=>y(b(`rpc/${t}`,o),u({method:"POST",headers:d(i),body:JSON.stringify(s)})),insert:({from:t,data:s,headers:i,baseUrl:o})=>y(b(t,o),u({method:"POST",headers:d(i),body:JSON.stringify(s)})),update:({from:t,data:s,params:i,method:o,headers:h,baseUrl:l})=>{const $=i?.id||s?.id,g=$?`${t}/${$}`:t;return y(b(g,l),u({method:o||"PATCH",headers:d(h),body:JSON.stringify(s)}))},upsert:({from:t,data:s,params:i,method:o,headers:h,baseUrl:l})=>{const $=i?.id||s?.id,g=$?`${t}/${$}`:t;return y(b(g,l),u({method:o||"PUT",headers:d(h),body:JSON.stringify(s)}))},delete:({from:t,params:s,headers:i,baseUrl:o})=>{const h=s?.id,l=h?`${t}/${h}`:t;return y(b(l,o),u({method:"DELETE",headers:p(i)}))}}};
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&&lt.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 S=(l,c,e)=>{const y=c&&!c.startsWith("/")?"/":"",r=new URL(`${l}${y}${c}`);if(e)for(const p in e){const o=e[p];o!=null&&r.searchParams.set(p,typeof o=="object"?JSON.stringify(o):o)}return r.toString()},h=async(l,c)=>{const e=await globalThis.fetch(l,c),y=e.headers.get("content-type"),r=y&&y.includes("json")?await e.json():await e.text();return{data:r,error:e.ok?null:r?.message||r?.error||e.statusText,status:e.status}},P=async({url:l,headers:c,auth:e,fetchOptions:y})=>{if(!l)throw new Error("@symbo.ls/fetch rest: url is required");return T(l,c,e,y)},T=(l,c={},e,y={})=>{let r=e?.token||null;const p=t=>{const s={...c,...t};return r&&(s.Authorization=`Bearer ${r}`),s},o=t=>({...p(t),"Content-Type":"application/json"}),d=t=>({...y,...t}),b=(t,s)=>{const n=s||l;if(t&&(t.startsWith("http://")||t.startsWith("https://")))return t;const a=t&&!t.startsWith("/")?"/":"";return`${n}${a}${t||""}`};return{name:"rest",setToken:t=>{r=t},getSession:async()=>{if(!e?.sessionUrl)return r?{token:r}:null;const t=await h(b(e.sessionUrl,e.baseUrl),d({headers:p()}));return t.error?null:t.data},signIn:async t=>{if(!e?.signInUrl)throw new Error("rest: auth.signInUrl not configured");const s=await h(b(e.signInUrl,e.baseUrl),d({method:"POST",headers:o(),body:JSON.stringify(t)}));return s.data?.token&&(r=s.data.token),s},signOut:async()=>(e?.signOutUrl&&await h(b(e.signOutUrl,e.baseUrl),d({method:"POST",headers:p()})),r=null,{error:null}),select:({from:t,params:s,select:n,limit:a,offset:u,order:i,single:$,headers:g,baseUrl:f})=>{const U={...s};return n&&(U.select=n),a&&(U.limit=a),u&&(U.offset=u),$&&(U.single=!0),i&&(typeof i=="string"?U.order=i:Array.isArray(i)?U.order=i.map(O=>`${O.by}:${O.asc===!1?"desc":"asc"}`).join(","):i.by&&(U.order=`${i.by}:${i.asc===!1?"desc":"asc"}`)),h(S(f||l,t||"",U),d({headers:p(g)}))},rpc:({from:t,params:s,headers:n,baseUrl:a})=>h(b(`rpc/${t}`,a),d({method:"POST",headers:o(n),body:JSON.stringify(s)})),insert:({from:t,data:s,headers:n,baseUrl:a})=>h(b(t,a),d({method:"POST",headers:o(n),body:JSON.stringify(s)})),update:({from:t,data:s,params:n,method:a,headers:u,baseUrl:i})=>{const $=n?.id||s?.id,g=$?`${t}/${$}`:t;return h(b(g,i),d({method:a||"PATCH",headers:o(u),body:JSON.stringify(s)}))},upsert:({from:t,data:s,params:n,method:a,headers:u,baseUrl:i})=>{const $=n?.id||s?.id,g=$?`${t}/${$}`:t;return h(b(g,i),d({method:a||"PUT",headers:o(u),body:JSON.stringify(s)}))},delete:({from:t,params:s,headers:n,baseUrl:a})=>{const u=s?.id,i=u?`${t}/${u}`:t;return h(b(i,a),d({method:"DELETE",headers:p(n)}))}}};export{T as restAdapter,P as setup};
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 (!element.__ref) return
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
- const cacheConfig = parseCacheConfig(cacheRaw)
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
- if (cacheKey) activeQueries.delete(cacheKey)
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 (config.refetchOnWindowFocus !== false) {
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 (config.refetchOnReconnect !== false) {
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
- if (data !== undefined) {
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 result = await fn({
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbo.ls/fetch",
3
- "version": "3.14.658",
3
+ "version": "3.14.660",
4
4
  "license": "CC-BY-NC-4.0",
5
5
  "type": "module",
6
6
  "module": "./dist/esm/index.js",