tanstack-fetch 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -3
- package/dist/cli.js +22 -239
- package/dist/client.type-BE-mgD4y.d.cts +116 -0
- package/dist/client.type-D1zw5tFf.d.ts +116 -0
- package/dist/config.type-eG_cuxpu.d.cts +132 -0
- package/dist/config.type-eG_cuxpu.d.ts +132 -0
- package/dist/index.cjs +2 -881
- package/dist/index.d.cts +20 -17
- package/dist/index.d.ts +20 -17
- package/dist/index.js +2 -3
- package/dist/plugins.cjs +1 -0
- package/dist/plugins.d.cts +19 -0
- package/dist/plugins.d.ts +19 -0
- package/dist/plugins.js +1 -0
- package/dist/react.cjs +1 -951
- package/dist/react.d.cts +6 -6
- package/dist/react.d.ts +6 -6
- package/dist/react.js +1 -91
- package/dist/sse.cjs +7 -0
- package/dist/sse.d.cts +9 -0
- package/dist/sse.d.ts +9 -0
- package/dist/sse.js +7 -0
- package/package.json +19 -6
- package/dist/chunk-T27KPHCL.js +0 -867
- package/dist/chunk-T27KPHCL.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/fetch-error-B10Od9AT.d.cts +0 -257
- package/dist/fetch-error-B10Od9AT.d.ts +0 -257
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/react.cjs.map +0 -1
- package/dist/react.js.map +0 -1
package/dist/chunk-T27KPHCL.js
DELETED
|
@@ -1,867 +0,0 @@
|
|
|
1
|
-
// src/plugins/auth.ts
|
|
2
|
-
var createAuthInterceptor = (auth) => ({
|
|
3
|
-
name: "auth",
|
|
4
|
-
order: 15,
|
|
5
|
-
onRequest: async (context) => {
|
|
6
|
-
const token = await auth.getToken();
|
|
7
|
-
if (!token) {
|
|
8
|
-
return { action: "continue", context };
|
|
9
|
-
}
|
|
10
|
-
const header = auth.header ?? "authorization";
|
|
11
|
-
const scheme = auth.scheme === void 0 ? "Bearer" : auth.scheme;
|
|
12
|
-
const value = scheme ? `${scheme} ${token}` : token;
|
|
13
|
-
context.request.headers.set(header, value);
|
|
14
|
-
return { action: "continue", context };
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
// src/plugins/status.ts
|
|
19
|
-
var resolveStatusHandler = (status, handlers) => {
|
|
20
|
-
const exact = handlers[status];
|
|
21
|
-
if (exact) {
|
|
22
|
-
return exact;
|
|
23
|
-
}
|
|
24
|
-
if (status >= 500 && status < 600 && handlers["5xx"]) {
|
|
25
|
-
return handlers["5xx"];
|
|
26
|
-
}
|
|
27
|
-
if (status >= 400 && status < 500 && handlers["4xx"]) {
|
|
28
|
-
return handlers["4xx"];
|
|
29
|
-
}
|
|
30
|
-
return handlers.default;
|
|
31
|
-
};
|
|
32
|
-
var createStatusInterceptor = (handlers) => ({
|
|
33
|
-
name: "on-status",
|
|
34
|
-
order: 95,
|
|
35
|
-
onResponseError: async (context) => {
|
|
36
|
-
const status = context.error?.status ?? context.response?.status;
|
|
37
|
-
if (status === void 0 || !context.error) {
|
|
38
|
-
return { action: "continue", context };
|
|
39
|
-
}
|
|
40
|
-
const handler = resolveStatusHandler(status, handlers);
|
|
41
|
-
if (!handler) {
|
|
42
|
-
return { action: "continue", context };
|
|
43
|
-
}
|
|
44
|
-
const decision = await handler({ status, error: context.error, context });
|
|
45
|
-
if (decision?.action === "retry") {
|
|
46
|
-
return { action: "retry", delayMs: decision.delayMs };
|
|
47
|
-
}
|
|
48
|
-
return { action: "continue", context };
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// src/constants.ts
|
|
53
|
-
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
54
|
-
var DEFAULT_MAX_RETRIES = 2;
|
|
55
|
-
var DEFAULT_INTERCEPTOR_ORDER = 100;
|
|
56
|
-
var IDEMPOTENT_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS"]);
|
|
57
|
-
var RETRY_STATUSES = /* @__PURE__ */ new Set([502, 503, 504]);
|
|
58
|
-
|
|
59
|
-
// src/plugins/retry-idempotent.ts
|
|
60
|
-
var createRetryIdempotentInterceptor = () => ({
|
|
61
|
-
name: "retry-idempotent",
|
|
62
|
-
order: 80,
|
|
63
|
-
onResponseError: (context) => {
|
|
64
|
-
const canRetry = IDEMPOTENT_METHODS.has(context.request.method) && context.meta.attempt < context.meta.maxRetries && Boolean(context.error && RETRY_STATUSES.has(context.error.status));
|
|
65
|
-
if (!canRetry) {
|
|
66
|
-
return { action: "continue", context };
|
|
67
|
-
}
|
|
68
|
-
return { action: "retry", delayMs: 200 * (context.meta.attempt + 1) };
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
// src/plugins/sse-resume.ts
|
|
73
|
-
var createSseResumeInterceptor = () => ({
|
|
74
|
-
name: "sse-resume",
|
|
75
|
-
order: 20,
|
|
76
|
-
onSseEvent: (context) => {
|
|
77
|
-
if (context.event.event === "ping" || context.event.event === "heartbeat") {
|
|
78
|
-
return { action: "drop" };
|
|
79
|
-
}
|
|
80
|
-
return { action: "continue", context };
|
|
81
|
-
},
|
|
82
|
-
onSseReconnect: (context) => {
|
|
83
|
-
if (context.meta.lastEventId) {
|
|
84
|
-
context.request.headers.set("last-event-id", context.meta.lastEventId);
|
|
85
|
-
}
|
|
86
|
-
return { action: "continue", context };
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
// src/plugins/ssr-forward.ts
|
|
91
|
-
var createSsrForwardInterceptor = () => ({
|
|
92
|
-
name: "ssr-forward",
|
|
93
|
-
order: 10,
|
|
94
|
-
onRequest: (context) => {
|
|
95
|
-
if (context.meta.source === "browser") {
|
|
96
|
-
return { action: "skip" };
|
|
97
|
-
}
|
|
98
|
-
if (context.incoming?.cookie) {
|
|
99
|
-
context.request.headers.set("cookie", context.incoming.cookie);
|
|
100
|
-
}
|
|
101
|
-
if (context.incoming?.authorization) {
|
|
102
|
-
context.request.headers.set("authorization", context.incoming.authorization);
|
|
103
|
-
}
|
|
104
|
-
if (context.incoming?.requestId) {
|
|
105
|
-
context.request.headers.set("x-request-id", context.incoming.requestId);
|
|
106
|
-
}
|
|
107
|
-
return { action: "continue", context };
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
// src/plugins/trace.ts
|
|
112
|
-
var createTraceInterceptor = () => ({
|
|
113
|
-
name: "trace",
|
|
114
|
-
order: 0,
|
|
115
|
-
onRequest: (context) => {
|
|
116
|
-
const requestId = context.incoming?.requestId ?? globalThis.crypto.randomUUID();
|
|
117
|
-
context.request.headers.set("x-request-id", requestId);
|
|
118
|
-
context.meta.requestId = requestId;
|
|
119
|
-
return { action: "continue", context };
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
// src/plugins/index.ts
|
|
124
|
-
var pluginFactories = {
|
|
125
|
-
trace: createTraceInterceptor,
|
|
126
|
-
"ssr-forward": createSsrForwardInterceptor,
|
|
127
|
-
"retry-idempotent": createRetryIdempotentInterceptor,
|
|
128
|
-
"sse-resume": createSseResumeInterceptor
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
// src/fetch-error.ts
|
|
132
|
-
var createFetchError = (result) => {
|
|
133
|
-
const info = result.ok ? {
|
|
134
|
-
status: result.status,
|
|
135
|
-
code: "UNKNOWN",
|
|
136
|
-
message: "Request failed",
|
|
137
|
-
body: result.data
|
|
138
|
-
} : result.error;
|
|
139
|
-
const error = new Error(info.message);
|
|
140
|
-
Object.defineProperties(error, {
|
|
141
|
-
name: { value: "FetchError" },
|
|
142
|
-
status: { value: info.status },
|
|
143
|
-
code: { value: info.code },
|
|
144
|
-
body: { value: info.body },
|
|
145
|
-
headers: { value: result.headers },
|
|
146
|
-
result: {
|
|
147
|
-
value: result.ok ? { ok: false, status: info.status, error: info, headers: result.headers } : result
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
return error;
|
|
151
|
-
};
|
|
152
|
-
var isFetchError = (error) => Boolean(
|
|
153
|
-
error && typeof error === "object" && error.name === "FetchError" && "status" in error && "code" in error
|
|
154
|
-
);
|
|
155
|
-
var isAbortError = (error) => error instanceof DOMException && error.name === "AbortError" || error instanceof Error && error.name === "AbortError";
|
|
156
|
-
|
|
157
|
-
// src/utils/result.ts
|
|
158
|
-
var toFetchErrorInfo = (status, body) => {
|
|
159
|
-
const record = body && typeof body === "object" ? body : void 0;
|
|
160
|
-
const code = typeof record?.code === "string" ? record.code : "HTTP_ERROR";
|
|
161
|
-
const message = typeof record?.message === "string" ? record.message : `Request failed with status ${status}`;
|
|
162
|
-
return { status, code, message, body };
|
|
163
|
-
};
|
|
164
|
-
var toOkResult = (status, data, headers) => ({
|
|
165
|
-
ok: true,
|
|
166
|
-
status,
|
|
167
|
-
data,
|
|
168
|
-
headers
|
|
169
|
-
});
|
|
170
|
-
var toErrResult = (status, error, headers) => ({
|
|
171
|
-
ok: false,
|
|
172
|
-
status,
|
|
173
|
-
error,
|
|
174
|
-
headers
|
|
175
|
-
});
|
|
176
|
-
var unwrap = (result) => {
|
|
177
|
-
if (result.ok) {
|
|
178
|
-
return result.data;
|
|
179
|
-
}
|
|
180
|
-
throw createFetchError(result);
|
|
181
|
-
};
|
|
182
|
-
var unwrapAsync = async (promise) => unwrap(await promise);
|
|
183
|
-
|
|
184
|
-
// src/plugins/config-interceptors.ts
|
|
185
|
-
var mergeStatusHandlers = (options) => {
|
|
186
|
-
const handlers = { ...options.onStatus ?? {} };
|
|
187
|
-
if (options.onUnauthorized && handlers[401] === void 0) {
|
|
188
|
-
handlers[401] = options.onUnauthorized;
|
|
189
|
-
}
|
|
190
|
-
if (options.onForbidden && handlers[403] === void 0) {
|
|
191
|
-
handlers[403] = options.onForbidden;
|
|
192
|
-
}
|
|
193
|
-
if (options.onNotFound && handlers[404] === void 0) {
|
|
194
|
-
handlers[404] = options.onNotFound;
|
|
195
|
-
}
|
|
196
|
-
if (options.onServerError && handlers["5xx"] === void 0 && handlers[500] === void 0) {
|
|
197
|
-
handlers["5xx"] = options.onServerError;
|
|
198
|
-
}
|
|
199
|
-
const hasHandler = Object.entries(handlers).some(([, handler]) => Boolean(handler));
|
|
200
|
-
return hasHandler ? handlers : void 0;
|
|
201
|
-
};
|
|
202
|
-
var resolveAuthConfig = (options) => {
|
|
203
|
-
if (options.auth) {
|
|
204
|
-
return options.auth;
|
|
205
|
-
}
|
|
206
|
-
if (options.getToken) {
|
|
207
|
-
return { getToken: options.getToken };
|
|
208
|
-
}
|
|
209
|
-
return void 0;
|
|
210
|
-
};
|
|
211
|
-
var createConfigInterceptors = (options) => {
|
|
212
|
-
const interceptors = [];
|
|
213
|
-
const auth = resolveAuthConfig(options);
|
|
214
|
-
if (auth) {
|
|
215
|
-
interceptors.push(createAuthInterceptor(auth));
|
|
216
|
-
}
|
|
217
|
-
const statusHandlers = mergeStatusHandlers(options);
|
|
218
|
-
if (statusHandlers) {
|
|
219
|
-
interceptors.push(createStatusInterceptor(statusHandlers));
|
|
220
|
-
}
|
|
221
|
-
return interceptors;
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
// src/interceptors/run-interceptors.ts
|
|
225
|
-
var matchesInterceptor = (interceptor, context) => {
|
|
226
|
-
const match = interceptor.match;
|
|
227
|
-
if (!match) {
|
|
228
|
-
return true;
|
|
229
|
-
}
|
|
230
|
-
if (match.operation && match.operation !== context.meta.operation) {
|
|
231
|
-
return false;
|
|
232
|
-
}
|
|
233
|
-
if (match.method && match.method !== context.request.method) {
|
|
234
|
-
return false;
|
|
235
|
-
}
|
|
236
|
-
if (match.pathPrefix && !context.request.url.pathname.startsWith(match.pathPrefix)) {
|
|
237
|
-
return false;
|
|
238
|
-
}
|
|
239
|
-
if (match.status !== void 0 && context.response?.status !== match.status) {
|
|
240
|
-
return false;
|
|
241
|
-
}
|
|
242
|
-
return true;
|
|
243
|
-
};
|
|
244
|
-
var resolveInterceptors = (clientInterceptors, extras) => {
|
|
245
|
-
const ejected = new Set(extras?.eject ?? []);
|
|
246
|
-
const merged = [...clientInterceptors, ...extras?.use ?? []].filter(
|
|
247
|
-
(item) => !ejected.has(item.name)
|
|
248
|
-
);
|
|
249
|
-
return merged.sort(
|
|
250
|
-
(left, right) => (left.order ?? DEFAULT_INTERCEPTOR_ORDER) - (right.order ?? DEFAULT_INTERCEPTOR_ORDER)
|
|
251
|
-
);
|
|
252
|
-
};
|
|
253
|
-
var runHook = async (interceptors, getHandler, context) => {
|
|
254
|
-
let current = context;
|
|
255
|
-
for (const interceptor of interceptors) {
|
|
256
|
-
if (!matchesInterceptor(interceptor, current)) {
|
|
257
|
-
continue;
|
|
258
|
-
}
|
|
259
|
-
const handler = getHandler(interceptor);
|
|
260
|
-
if (!handler) {
|
|
261
|
-
continue;
|
|
262
|
-
}
|
|
263
|
-
const decision = await handler(current) ?? { action: "continue", context: current };
|
|
264
|
-
if (decision.action === "skip") {
|
|
265
|
-
continue;
|
|
266
|
-
}
|
|
267
|
-
if (decision.action === "drop") {
|
|
268
|
-
return { type: "drop" };
|
|
269
|
-
}
|
|
270
|
-
if (decision.action === "retry") {
|
|
271
|
-
return { type: "retry", delayMs: decision.delayMs };
|
|
272
|
-
}
|
|
273
|
-
if (decision.action === "short-circuit") {
|
|
274
|
-
return { type: "short-circuit", result: decision.result };
|
|
275
|
-
}
|
|
276
|
-
current = decision.context ?? current;
|
|
277
|
-
}
|
|
278
|
-
return { type: "continue", context: current };
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
// src/utils/parse-body.ts
|
|
282
|
-
var isJsonContentType = (contentType) => Boolean(contentType && contentType.includes("json"));
|
|
283
|
-
var parseBody = async (response, parseAs) => {
|
|
284
|
-
if (response.status === 204) {
|
|
285
|
-
return null;
|
|
286
|
-
}
|
|
287
|
-
if (parseAs === "blob") {
|
|
288
|
-
return response.blob();
|
|
289
|
-
}
|
|
290
|
-
if (parseAs === "text") {
|
|
291
|
-
return response.text();
|
|
292
|
-
}
|
|
293
|
-
const contentType = response.headers.get("content-type");
|
|
294
|
-
if (parseAs === "json" || isJsonContentType(contentType)) {
|
|
295
|
-
const text = await response.text();
|
|
296
|
-
if (!text) {
|
|
297
|
-
return null;
|
|
298
|
-
}
|
|
299
|
-
return JSON.parse(text);
|
|
300
|
-
}
|
|
301
|
-
return response.text();
|
|
302
|
-
};
|
|
303
|
-
var encodeBody = (body, headers) => {
|
|
304
|
-
if (body === void 0 || body === null) {
|
|
305
|
-
return void 0;
|
|
306
|
-
}
|
|
307
|
-
if (typeof body === "string" || body instanceof FormData || body instanceof Blob || body instanceof URLSearchParams || body instanceof ArrayBuffer) {
|
|
308
|
-
return body;
|
|
309
|
-
}
|
|
310
|
-
if (!headers.has("content-type")) {
|
|
311
|
-
headers.set("content-type", "application/json");
|
|
312
|
-
}
|
|
313
|
-
return JSON.stringify(body);
|
|
314
|
-
};
|
|
315
|
-
|
|
316
|
-
// src/request-execute.ts
|
|
317
|
-
var executeFetch = async (input) => {
|
|
318
|
-
const { context, interceptors, fetchImpl, client, requestOptions } = input;
|
|
319
|
-
try {
|
|
320
|
-
const response = await fetchImpl(context.request.url, {
|
|
321
|
-
method: context.request.method,
|
|
322
|
-
headers: context.request.headers,
|
|
323
|
-
body: encodeBody(context.request.body, context.request.headers),
|
|
324
|
-
signal: context.request.signal,
|
|
325
|
-
credentials: client.credentials
|
|
326
|
-
});
|
|
327
|
-
return handleResponse({ interceptors, context, response, requestOptions });
|
|
328
|
-
} catch (error) {
|
|
329
|
-
if (isAbortError(error)) {
|
|
330
|
-
throw error;
|
|
331
|
-
}
|
|
332
|
-
context.error = toFetchErrorInfo(0, {
|
|
333
|
-
code: "NETWORK_ERROR",
|
|
334
|
-
message: error instanceof Error ? error.message : "Network error"
|
|
335
|
-
});
|
|
336
|
-
const failed = await runHook(interceptors, (item) => item.onRequestError, context);
|
|
337
|
-
if (failed.type === "retry") {
|
|
338
|
-
return { kind: "retry", delayMs: failed.delayMs };
|
|
339
|
-
}
|
|
340
|
-
if (failed.type === "short-circuit") {
|
|
341
|
-
return { kind: "result", result: failed.result };
|
|
342
|
-
}
|
|
343
|
-
throw createFetchError(
|
|
344
|
-
toErrResult(0, context.error, new Headers())
|
|
345
|
-
);
|
|
346
|
-
}
|
|
347
|
-
};
|
|
348
|
-
var handleResponse = async (input) => {
|
|
349
|
-
const { interceptors, response, requestOptions } = input;
|
|
350
|
-
const context = {
|
|
351
|
-
...input.context,
|
|
352
|
-
response,
|
|
353
|
-
data: await parseBody(response, requestOptions?.parseAs)
|
|
354
|
-
};
|
|
355
|
-
const hook = response.ok ? (item) => item.onResponse : (item) => item.onResponseError;
|
|
356
|
-
if (!response.ok) {
|
|
357
|
-
context.error = toFetchErrorInfo(response.status, context.data);
|
|
358
|
-
}
|
|
359
|
-
const after = await runHook(interceptors, hook, context);
|
|
360
|
-
if (after.type === "retry") {
|
|
361
|
-
return { kind: "retry", delayMs: after.delayMs };
|
|
362
|
-
}
|
|
363
|
-
if (after.type === "short-circuit") {
|
|
364
|
-
return { kind: "result", result: after.result };
|
|
365
|
-
}
|
|
366
|
-
const nextContext = after.type === "continue" ? after.context : context;
|
|
367
|
-
const result = response.ok ? toOkResult(response.status, nextContext.data, response.headers) : toErrResult(
|
|
368
|
-
response.status,
|
|
369
|
-
nextContext.error ?? toFetchErrorInfo(response.status, nextContext.data),
|
|
370
|
-
response.headers
|
|
371
|
-
);
|
|
372
|
-
return { kind: "result", result };
|
|
373
|
-
};
|
|
374
|
-
|
|
375
|
-
// src/utils/build-url.ts
|
|
376
|
-
var fillPath = (path, params) => {
|
|
377
|
-
return path.replace(/:([A-Za-z0-9_]+)/g, (_match, key) => {
|
|
378
|
-
const value = params?.[key];
|
|
379
|
-
if (value === void 0) {
|
|
380
|
-
throw new Error(`tanstack-fetch: missing path param "${key}"`);
|
|
381
|
-
}
|
|
382
|
-
return encodeURIComponent(String(value));
|
|
383
|
-
});
|
|
384
|
-
};
|
|
385
|
-
var appendQuery = (url, query) => {
|
|
386
|
-
if (!query) {
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
Object.entries(query).forEach(([key, value]) => {
|
|
390
|
-
if (value === void 0 || value === null) {
|
|
391
|
-
return;
|
|
392
|
-
}
|
|
393
|
-
url.searchParams.set(key, String(value));
|
|
394
|
-
});
|
|
395
|
-
};
|
|
396
|
-
var assertAbsoluteUrl = (baseUrl, source) => {
|
|
397
|
-
if (source === "browser" || !baseUrl) {
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
if (!/^https?:\/\//i.test(baseUrl)) {
|
|
401
|
-
throw new Error("tanstack-fetch: set an absolute baseUrl for SSR and Edge runtimes");
|
|
402
|
-
}
|
|
403
|
-
};
|
|
404
|
-
var buildUrl = (baseUrl, path, params, query) => {
|
|
405
|
-
const filledPath = fillPath(path.replace(/\{([A-Za-z0-9_]+)\}/g, ":$1"), params);
|
|
406
|
-
const absolutePath = /^https?:\/\//i.test(filledPath) ? filledPath : `${(baseUrl ?? "").replace(/\/$/, "")}/${filledPath.replace(/^\//, "")}`;
|
|
407
|
-
const url = new URL(absolutePath);
|
|
408
|
-
appendQuery(url, query);
|
|
409
|
-
return url;
|
|
410
|
-
};
|
|
411
|
-
|
|
412
|
-
// src/utils/headers.ts
|
|
413
|
-
var toHeaders = (init) => new Headers(init);
|
|
414
|
-
var mergeHeaders = (...inits) => {
|
|
415
|
-
const headers = new Headers();
|
|
416
|
-
inits.forEach((init) => {
|
|
417
|
-
if (!init) {
|
|
418
|
-
return;
|
|
419
|
-
}
|
|
420
|
-
new Headers(init).forEach((value, key) => {
|
|
421
|
-
headers.set(key, value);
|
|
422
|
-
});
|
|
423
|
-
});
|
|
424
|
-
return headers;
|
|
425
|
-
};
|
|
426
|
-
var resolveHeaders = async (value) => {
|
|
427
|
-
if (!value) {
|
|
428
|
-
return new Headers();
|
|
429
|
-
}
|
|
430
|
-
const resolved = typeof value === "function" ? await value() : value;
|
|
431
|
-
return toHeaders(resolved);
|
|
432
|
-
};
|
|
433
|
-
|
|
434
|
-
// src/utils/signals.ts
|
|
435
|
-
var wait = (delayMs) => new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
436
|
-
var combineSignals = (signals) => {
|
|
437
|
-
const active = signals.filter((signal) => Boolean(signal));
|
|
438
|
-
if (active.length === 0) {
|
|
439
|
-
return void 0;
|
|
440
|
-
}
|
|
441
|
-
if (active.length === 1) {
|
|
442
|
-
return active[0];
|
|
443
|
-
}
|
|
444
|
-
if (typeof AbortSignal.any === "function") {
|
|
445
|
-
return AbortSignal.any(active);
|
|
446
|
-
}
|
|
447
|
-
const controller = new AbortController();
|
|
448
|
-
active.forEach((signal) => {
|
|
449
|
-
if (signal.aborted) {
|
|
450
|
-
controller.abort(signal.reason);
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
signal.addEventListener("abort", () => controller.abort(signal.reason), { once: true });
|
|
454
|
-
});
|
|
455
|
-
return controller.signal;
|
|
456
|
-
};
|
|
457
|
-
var createTimeoutSignal = (timeoutMs) => {
|
|
458
|
-
if (!timeoutMs || timeoutMs <= 0) {
|
|
459
|
-
return void 0;
|
|
460
|
-
}
|
|
461
|
-
const controller = new AbortController();
|
|
462
|
-
const timer = setTimeout(
|
|
463
|
-
() => controller.abort(new Error("tanstack-fetch: request timed out")),
|
|
464
|
-
timeoutMs
|
|
465
|
-
);
|
|
466
|
-
controller.signal.addEventListener("abort", () => clearTimeout(timer), { once: true });
|
|
467
|
-
return controller.signal;
|
|
468
|
-
};
|
|
469
|
-
|
|
470
|
-
// src/request.ts
|
|
471
|
-
var resolveIncoming = async (client) => {
|
|
472
|
-
if (!client.incoming) {
|
|
473
|
-
return void 0;
|
|
474
|
-
}
|
|
475
|
-
return typeof client.incoming === "function" ? client.incoming() : client.incoming;
|
|
476
|
-
};
|
|
477
|
-
var createContext = async (args, attempt) => {
|
|
478
|
-
const { method, path, requestOptions, client } = args;
|
|
479
|
-
const source = client.source ?? "browser";
|
|
480
|
-
assertAbsoluteUrl(client.baseUrl, source);
|
|
481
|
-
const url = buildUrl(client.baseUrl, path, requestOptions?.params, requestOptions?.query);
|
|
482
|
-
const headers = mergeHeaders(await resolveHeaders(client.headers), requestOptions?.headers);
|
|
483
|
-
const timeoutMs = requestOptions?.timeoutMs ?? client.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
484
|
-
const signal = combineSignals([requestOptions?.signal, createTimeoutSignal(timeoutMs)]);
|
|
485
|
-
return {
|
|
486
|
-
request: { method, url, headers, body: requestOptions?.body, signal },
|
|
487
|
-
incoming: await resolveIncoming(client),
|
|
488
|
-
meta: {
|
|
489
|
-
attempt,
|
|
490
|
-
maxRetries: client.maxRetries ?? DEFAULT_MAX_RETRIES,
|
|
491
|
-
source,
|
|
492
|
-
operation: requestOptions?.operation
|
|
493
|
-
}
|
|
494
|
-
};
|
|
495
|
-
};
|
|
496
|
-
var sendRequest = async (args) => {
|
|
497
|
-
const interceptors = resolveInterceptors(args.interceptors, args.requestOptions?.interceptors);
|
|
498
|
-
const fetchImpl = args.client.fetch ?? globalThis.fetch;
|
|
499
|
-
if (!fetchImpl) {
|
|
500
|
-
throw new Error("tanstack-fetch: fetch is not available");
|
|
501
|
-
}
|
|
502
|
-
let attempt = 0;
|
|
503
|
-
const maxRetries = args.client.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
504
|
-
while (attempt <= maxRetries) {
|
|
505
|
-
const outcome = await runAttempt({ args, interceptors, fetchImpl, attempt });
|
|
506
|
-
if (outcome.kind === "result") {
|
|
507
|
-
return outcome.result;
|
|
508
|
-
}
|
|
509
|
-
attempt += 1;
|
|
510
|
-
if (outcome.delayMs) {
|
|
511
|
-
await wait(outcome.delayMs);
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
throw new Error("tanstack-fetch: exceeded retry budget");
|
|
515
|
-
};
|
|
516
|
-
var runAttempt = async (input) => {
|
|
517
|
-
let context = await createContext(input.args, input.attempt);
|
|
518
|
-
const before = await runHook(input.interceptors, (item) => item.onRequest, context);
|
|
519
|
-
if (before.type === "short-circuit") {
|
|
520
|
-
return { kind: "result", result: before.result };
|
|
521
|
-
}
|
|
522
|
-
if (before.type === "retry") {
|
|
523
|
-
return { kind: "retry", delayMs: before.delayMs };
|
|
524
|
-
}
|
|
525
|
-
if (before.type === "continue") {
|
|
526
|
-
context = before.context;
|
|
527
|
-
}
|
|
528
|
-
return executeFetch({
|
|
529
|
-
requestOptions: input.args.requestOptions,
|
|
530
|
-
client: input.args.client,
|
|
531
|
-
interceptors: input.interceptors,
|
|
532
|
-
fetchImpl: input.fetchImpl,
|
|
533
|
-
context
|
|
534
|
-
});
|
|
535
|
-
};
|
|
536
|
-
|
|
537
|
-
// src/sse-parse.ts
|
|
538
|
-
var parseSseBlock = (block) => {
|
|
539
|
-
const dataLines = [];
|
|
540
|
-
let eventName;
|
|
541
|
-
let id;
|
|
542
|
-
let retry;
|
|
543
|
-
block.split("\n").forEach((line) => {
|
|
544
|
-
if (line.startsWith(":")) {
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
|
-
if (line.startsWith("data:")) {
|
|
548
|
-
dataLines.push(line.slice(5).replace(/^ /, ""));
|
|
549
|
-
return;
|
|
550
|
-
}
|
|
551
|
-
if (line.startsWith("event:")) {
|
|
552
|
-
eventName = line.slice(6).replace(/^ /, "");
|
|
553
|
-
return;
|
|
554
|
-
}
|
|
555
|
-
if (line.startsWith("id:")) {
|
|
556
|
-
id = line.slice(3).replace(/^ /, "");
|
|
557
|
-
return;
|
|
558
|
-
}
|
|
559
|
-
if (line.startsWith("retry:")) {
|
|
560
|
-
const parsed = Number.parseInt(line.slice(6).trim(), 10);
|
|
561
|
-
if (!Number.isNaN(parsed)) {
|
|
562
|
-
retry = parsed;
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
});
|
|
566
|
-
if (dataLines.length === 0 && !eventName) {
|
|
567
|
-
return void 0;
|
|
568
|
-
}
|
|
569
|
-
const raw = dataLines.join("\n");
|
|
570
|
-
let data = raw;
|
|
571
|
-
if (raw) {
|
|
572
|
-
try {
|
|
573
|
-
data = JSON.parse(raw);
|
|
574
|
-
} catch {
|
|
575
|
-
data = raw;
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
return { event: eventName, data, id, retry };
|
|
579
|
-
};
|
|
580
|
-
var consumeSseBuffer = (buffer) => {
|
|
581
|
-
const normalized = buffer.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
582
|
-
const chunks = normalized.split("\n\n");
|
|
583
|
-
const rest = chunks.pop() ?? "";
|
|
584
|
-
const events = chunks.map((block) => parseSseBlock(block.trim())).filter((event) => Boolean(event));
|
|
585
|
-
return { events, rest };
|
|
586
|
-
};
|
|
587
|
-
|
|
588
|
-
// src/sse-context.ts
|
|
589
|
-
var resolveIncoming2 = async (client) => {
|
|
590
|
-
if (!client.incoming) {
|
|
591
|
-
return void 0;
|
|
592
|
-
}
|
|
593
|
-
return typeof client.incoming === "function" ? client.incoming() : client.incoming;
|
|
594
|
-
};
|
|
595
|
-
var createSseContext = async (args, attempt, lastEventId) => {
|
|
596
|
-
const source = args.client.source ?? "browser";
|
|
597
|
-
assertAbsoluteUrl(args.client.baseUrl, source);
|
|
598
|
-
const url = buildUrl(
|
|
599
|
-
args.client.baseUrl,
|
|
600
|
-
args.path,
|
|
601
|
-
args.requestOptions?.params,
|
|
602
|
-
args.requestOptions?.query
|
|
603
|
-
);
|
|
604
|
-
const headers = mergeHeaders(
|
|
605
|
-
await resolveHeaders(args.client.headers),
|
|
606
|
-
args.requestOptions?.headers
|
|
607
|
-
);
|
|
608
|
-
headers.set("accept", "text/event-stream");
|
|
609
|
-
if (lastEventId) {
|
|
610
|
-
headers.set("last-event-id", lastEventId);
|
|
611
|
-
}
|
|
612
|
-
return {
|
|
613
|
-
request: {
|
|
614
|
-
method: "GET",
|
|
615
|
-
url,
|
|
616
|
-
headers,
|
|
617
|
-
body: args.requestOptions?.body,
|
|
618
|
-
signal: args.requestOptions?.signal
|
|
619
|
-
},
|
|
620
|
-
incoming: await resolveIncoming2(args.client),
|
|
621
|
-
meta: {
|
|
622
|
-
attempt,
|
|
623
|
-
maxRetries: args.client.maxRetries ?? DEFAULT_MAX_RETRIES,
|
|
624
|
-
source,
|
|
625
|
-
operation: args.requestOptions?.operation,
|
|
626
|
-
lastEventId
|
|
627
|
-
}
|
|
628
|
-
};
|
|
629
|
-
};
|
|
630
|
-
|
|
631
|
-
// src/sse-iterator.ts
|
|
632
|
-
var createSseIterator = (args) => {
|
|
633
|
-
const interceptors = resolveInterceptors(args.interceptors, args.requestOptions?.interceptors);
|
|
634
|
-
const fetchImpl = args.client.fetch ?? globalThis.fetch;
|
|
635
|
-
const queue = [];
|
|
636
|
-
let reader;
|
|
637
|
-
let buffer = "";
|
|
638
|
-
let lastEventId = args.requestOptions?.headers ? new Headers(args.requestOptions.headers).get("last-event-id") ?? void 0 : void 0;
|
|
639
|
-
let attempt = 0;
|
|
640
|
-
let closed = false;
|
|
641
|
-
const pull = async () => {
|
|
642
|
-
if (queue.length > 0) {
|
|
643
|
-
return { value: queue.shift(), done: false };
|
|
644
|
-
}
|
|
645
|
-
if (closed) {
|
|
646
|
-
return { value: void 0, done: true };
|
|
647
|
-
}
|
|
648
|
-
if (!reader) {
|
|
649
|
-
const started = await openStream();
|
|
650
|
-
if (!started) {
|
|
651
|
-
closed = true;
|
|
652
|
-
return { value: void 0, done: true };
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
return readNext();
|
|
656
|
-
};
|
|
657
|
-
const openStream = async () => {
|
|
658
|
-
if (!fetchImpl) {
|
|
659
|
-
throw new Error("tanstack-fetch: fetch is not available");
|
|
660
|
-
}
|
|
661
|
-
let context = await createSseContext(args, attempt, lastEventId);
|
|
662
|
-
const before = await runHook(interceptors, (item) => item.onRequest, context);
|
|
663
|
-
if (before.type === "short-circuit" || before.type === "retry") {
|
|
664
|
-
return false;
|
|
665
|
-
}
|
|
666
|
-
if (before.type === "continue") {
|
|
667
|
-
context = before.context;
|
|
668
|
-
}
|
|
669
|
-
const response = await fetchImpl(context.request.url, {
|
|
670
|
-
method: "GET",
|
|
671
|
-
headers: context.request.headers,
|
|
672
|
-
signal: context.request.signal,
|
|
673
|
-
credentials: args.client.credentials
|
|
674
|
-
});
|
|
675
|
-
context.response = response;
|
|
676
|
-
if (!response.ok || !response.body) {
|
|
677
|
-
context.error = toFetchErrorInfo(response.status, await response.text());
|
|
678
|
-
const failed = await runHook(interceptors, (item) => item.onSseError, context);
|
|
679
|
-
if (failed.type === "retry" && attempt < context.meta.maxRetries) {
|
|
680
|
-
attempt += 1;
|
|
681
|
-
await wait(failed.delayMs ?? 500);
|
|
682
|
-
const reconnect = await runHook(interceptors, (item) => item.onSseReconnect, context);
|
|
683
|
-
if (reconnect.type === "continue") {
|
|
684
|
-
lastEventId = reconnect.context.meta.lastEventId ?? lastEventId;
|
|
685
|
-
}
|
|
686
|
-
return openStream();
|
|
687
|
-
}
|
|
688
|
-
throw Object.assign(new Error(context.error.message), { error: context.error });
|
|
689
|
-
}
|
|
690
|
-
await runHook(interceptors, (item) => item.onSseOpen, context);
|
|
691
|
-
reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
|
|
692
|
-
return true;
|
|
693
|
-
};
|
|
694
|
-
const readNext = async () => {
|
|
695
|
-
const currentReader = reader;
|
|
696
|
-
if (!currentReader) {
|
|
697
|
-
closed = true;
|
|
698
|
-
return { value: void 0, done: true };
|
|
699
|
-
}
|
|
700
|
-
const chunk = await currentReader.read();
|
|
701
|
-
if (chunk.done) {
|
|
702
|
-
reader = void 0;
|
|
703
|
-
closed = true;
|
|
704
|
-
return pull();
|
|
705
|
-
}
|
|
706
|
-
const parsed = consumeSseBuffer(buffer + chunk.value);
|
|
707
|
-
buffer = parsed.rest;
|
|
708
|
-
for (const event of parsed.events) {
|
|
709
|
-
lastEventId = event.id ?? lastEventId;
|
|
710
|
-
const context = await createSseContext(args, attempt, lastEventId);
|
|
711
|
-
const after = await runHook(interceptors, (item) => item.onSseEvent, { ...context, event });
|
|
712
|
-
if (after.type === "drop") {
|
|
713
|
-
continue;
|
|
714
|
-
}
|
|
715
|
-
if (after.type === "continue" && after.context.event) {
|
|
716
|
-
queue.push(after.context.event);
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
return pull();
|
|
720
|
-
};
|
|
721
|
-
return { next: pull };
|
|
722
|
-
};
|
|
723
|
-
|
|
724
|
-
// src/sse.ts
|
|
725
|
-
var sendSse = (args) => ({
|
|
726
|
-
[Symbol.asyncIterator]: () => createSseIterator(args)
|
|
727
|
-
});
|
|
728
|
-
|
|
729
|
-
// src/sse-listen.ts
|
|
730
|
-
var HANDLER_KEYS = ["onMessage", "onEvent", "onOpen", "onError", "onClose", "lastEventId"];
|
|
731
|
-
var splitSseOptions = (options) => {
|
|
732
|
-
const handlers = {};
|
|
733
|
-
const requestOptions = { ...options ?? {} };
|
|
734
|
-
const lastEventId = options?.lastEventId;
|
|
735
|
-
for (const key of HANDLER_KEYS) {
|
|
736
|
-
if (key === "lastEventId") {
|
|
737
|
-
delete requestOptions.lastEventId;
|
|
738
|
-
continue;
|
|
739
|
-
}
|
|
740
|
-
if (options && key in options) {
|
|
741
|
-
handlers[key] = options[key];
|
|
742
|
-
delete requestOptions[key];
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
if (lastEventId) {
|
|
746
|
-
const headers = new Headers(requestOptions.headers);
|
|
747
|
-
headers.set("last-event-id", lastEventId);
|
|
748
|
-
requestOptions.headers = headers;
|
|
749
|
-
}
|
|
750
|
-
return { handlers, requestOptions, lastEventId };
|
|
751
|
-
};
|
|
752
|
-
var hasSseHandlers = (options) => Boolean(
|
|
753
|
-
options && (options.onMessage || options.onEvent || options.onOpen || options.onError || options.onClose)
|
|
754
|
-
);
|
|
755
|
-
var listenSse = (args, handlers) => {
|
|
756
|
-
const controller = new AbortController();
|
|
757
|
-
const signal = combineSignals([args.requestOptions?.signal, controller.signal]);
|
|
758
|
-
const run = async () => {
|
|
759
|
-
try {
|
|
760
|
-
handlers.onOpen?.();
|
|
761
|
-
for await (const event of sendSse({
|
|
762
|
-
...args,
|
|
763
|
-
requestOptions: { ...args.requestOptions, signal }
|
|
764
|
-
})) {
|
|
765
|
-
handlers.onEvent?.(event);
|
|
766
|
-
handlers.onMessage?.(event.data, event);
|
|
767
|
-
}
|
|
768
|
-
handlers.onClose?.();
|
|
769
|
-
} catch (error) {
|
|
770
|
-
if (isAbortError(error) || controller.signal.aborted) {
|
|
771
|
-
handlers.onClose?.();
|
|
772
|
-
return;
|
|
773
|
-
}
|
|
774
|
-
handlers.onError?.(error);
|
|
775
|
-
}
|
|
776
|
-
};
|
|
777
|
-
void run();
|
|
778
|
-
return {
|
|
779
|
-
close: () => controller.abort()
|
|
780
|
-
};
|
|
781
|
-
};
|
|
782
|
-
var createSseApi = (base) => {
|
|
783
|
-
const sse = ((path, options) => {
|
|
784
|
-
const { handlers, requestOptions } = splitSseOptions(options);
|
|
785
|
-
const args = {
|
|
786
|
-
path,
|
|
787
|
-
requestOptions,
|
|
788
|
-
client: base.client,
|
|
789
|
-
interceptors: base.interceptors
|
|
790
|
-
};
|
|
791
|
-
if (hasSseHandlers(options)) {
|
|
792
|
-
return listenSse(args, handlers);
|
|
793
|
-
}
|
|
794
|
-
return sendSse(args);
|
|
795
|
-
});
|
|
796
|
-
return sse;
|
|
797
|
-
};
|
|
798
|
-
|
|
799
|
-
// src/create-fetch.ts
|
|
800
|
-
var createFetch = (options = {}) => {
|
|
801
|
-
const clientOptions = {
|
|
802
|
-
throwOnError: true,
|
|
803
|
-
...options
|
|
804
|
-
};
|
|
805
|
-
const interceptors = [
|
|
806
|
-
...createConfigInterceptors(clientOptions),
|
|
807
|
-
...(clientOptions.plugins ?? []).map((name) => pluginFactories[name]()),
|
|
808
|
-
...clientOptions.interceptors ?? []
|
|
809
|
-
];
|
|
810
|
-
const use = (name, interceptor, config) => {
|
|
811
|
-
const next = {
|
|
812
|
-
...interceptor,
|
|
813
|
-
name,
|
|
814
|
-
order: config?.order ?? interceptor.order
|
|
815
|
-
};
|
|
816
|
-
const existing = interceptors.findIndex((item) => item.name === name);
|
|
817
|
-
if (existing >= 0) {
|
|
818
|
-
interceptors.splice(existing, 1, next);
|
|
819
|
-
return;
|
|
820
|
-
}
|
|
821
|
-
interceptors.push(next);
|
|
822
|
-
};
|
|
823
|
-
const eject = (name) => {
|
|
824
|
-
const index = interceptors.findIndex((item) => item.name === name);
|
|
825
|
-
if (index >= 0) {
|
|
826
|
-
interceptors.splice(index, 1);
|
|
827
|
-
}
|
|
828
|
-
};
|
|
829
|
-
const request = (async (method, path, requestOptions) => {
|
|
830
|
-
const result = await sendRequest({
|
|
831
|
-
method,
|
|
832
|
-
path,
|
|
833
|
-
requestOptions,
|
|
834
|
-
client: clientOptions,
|
|
835
|
-
interceptors
|
|
836
|
-
});
|
|
837
|
-
const shouldThrow = requestOptions?.throwOnError ?? clientOptions.throwOnError ?? true;
|
|
838
|
-
if (!result.ok && shouldThrow) {
|
|
839
|
-
throw createFetchError(result);
|
|
840
|
-
}
|
|
841
|
-
if (shouldThrow && result.ok) {
|
|
842
|
-
return result.data;
|
|
843
|
-
}
|
|
844
|
-
return result;
|
|
845
|
-
});
|
|
846
|
-
const bindMethod = (httpMethod) => {
|
|
847
|
-
const bound = (path, requestOptions) => request(httpMethod, path, requestOptions);
|
|
848
|
-
return bound;
|
|
849
|
-
};
|
|
850
|
-
const sse = createSseApi({ client: clientOptions, interceptors });
|
|
851
|
-
return {
|
|
852
|
-
use,
|
|
853
|
-
eject,
|
|
854
|
-
request,
|
|
855
|
-
get: bindMethod("GET"),
|
|
856
|
-
post: bindMethod("POST"),
|
|
857
|
-
put: bindMethod("PUT"),
|
|
858
|
-
patch: bindMethod("PATCH"),
|
|
859
|
-
delete: bindMethod("DELETE"),
|
|
860
|
-
sse
|
|
861
|
-
};
|
|
862
|
-
};
|
|
863
|
-
var createClient = createFetch;
|
|
864
|
-
|
|
865
|
-
export { createAuthInterceptor, createClient, createFetch, createFetchError, createRetryIdempotentInterceptor, createSseResumeInterceptor, createSsrForwardInterceptor, createStatusInterceptor, createTraceInterceptor, isAbortError, isFetchError, unwrap, unwrapAsync };
|
|
866
|
-
//# sourceMappingURL=chunk-T27KPHCL.js.map
|
|
867
|
-
//# sourceMappingURL=chunk-T27KPHCL.js.map
|