@spfn/core 0.3.0-beta.2 → 0.3.0-beta.21
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 +343 -16
- package/dist/app-config/index.d.ts +134 -0
- package/dist/app-config/index.js +58 -0
- package/dist/app-config/index.js.map +1 -0
- package/dist/authz/index.js +1 -381
- package/dist/authz/index.js.map +1 -1
- package/dist/{boss-D16fO2oG.d.ts → boss-BiDCbbAQ.d.ts} +60 -7
- package/dist/codegen/index.d.ts +93 -15
- package/dist/codegen/index.js +626 -165
- package/dist/codegen/index.js.map +1 -1
- package/dist/config/index.d.ts +0 -63
- package/dist/config/index.js +15 -15
- package/dist/config/index.js.map +1 -1
- package/dist/contract/index.d.ts +40 -17
- package/dist/contract/index.js +147 -23
- package/dist/contract/index.js.map +1 -1
- package/dist/db/index.d.ts +201 -34
- package/dist/db/index.js +294 -158
- package/dist/db/index.js.map +1 -1
- package/dist/{define-middleware-DfDP39Nq.d.ts → define-middleware-CVKgqo8S.d.ts} +1 -1
- package/dist/env/index.d.ts +6 -442
- package/dist/env/index.js +13 -16
- package/dist/env/index.js.map +1 -1
- package/dist/env/loader.js +24 -1
- package/dist/env/loader.js.map +1 -1
- package/dist/error-TsUIjp_x.d.ts +157 -0
- package/dist/errors/index.js +1 -381
- package/dist/errors/index.js.map +1 -1
- package/dist/event/index.d.ts +5 -5
- package/dist/event/index.js +32 -1
- package/dist/event/index.js.map +1 -1
- package/dist/event/sse/client.d.ts +18 -4
- package/dist/event/sse/client.js +38 -2
- package/dist/event/sse/client.js.map +1 -1
- package/dist/event/sse/index.d.ts +5 -4
- package/dist/event/ws/client.d.ts +3 -2
- package/dist/event/ws/index.d.ts +4 -3
- package/dist/job/index.d.ts +48 -3
- package/dist/job/index.js +131 -52
- package/dist/job/index.js.map +1 -1
- package/dist/logger/index.js +0 -12
- package/dist/logger/index.js.map +1 -1
- package/dist/middleware/index.d.ts +6 -2
- package/dist/middleware/index.js +7 -388
- package/dist/middleware/index.js.map +1 -1
- package/dist/nextjs/index.d.ts +88 -8
- package/dist/nextjs/index.js +138 -62
- package/dist/nextjs/index.js.map +1 -1
- package/dist/nextjs/server.d.ts +45 -7
- package/dist/nextjs/server.js +14 -0
- package/dist/nextjs/server.js.map +1 -1
- package/dist/ops/index.d.ts +62 -43
- package/dist/ops/index.js +638 -97
- package/dist/ops/index.js.map +1 -1
- package/dist/registry-C2KQCh0m.d.ts +473 -0
- package/dist/route/index.d.ts +6 -3
- package/dist/route/index.js +97 -28
- package/dist/route/index.js.map +1 -1
- package/dist/route/types.d.ts +7 -1
- package/dist/{router-Qbssr11H.d.ts → route-builder-DRW-MSCJ.d.ts} +52 -127
- package/dist/router-4YoIy5fN.d.ts +172 -0
- package/dist/{token-manager-BT5EnUAR.d.ts → router-CysBmgv3.d.ts} +81 -127
- package/dist/server/index.d.ts +185 -14
- package/dist/server/index.js +883 -78
- package/dist/server/index.js.map +1 -1
- package/dist/surface/index.d.ts +115 -0
- package/dist/surface/index.js +1003 -0
- package/dist/surface/index.js.map +1 -0
- package/dist/token-manager-Ckjt2-qq.d.ts +122 -0
- package/dist/{types-D1c57Ko-.d.ts → types-5Rl11_Nb.d.ts} +43 -4
- package/dist/{types-ZQODsBft.d.ts → types-B8zAxFsE.d.ts} +2 -1
- package/dist/types-CxhPH4s_.d.ts +375 -0
- package/dist/{types-2AbaW4Ie.d.ts → types-W4u_S0lF.d.ts} +4 -3
- package/docs/file-upload.md +195 -333
- package/package.json +20 -9
- package/src/cache/README.md +330 -0
- package/src/codegen/README.md +634 -0
- package/src/config/README.md +333 -0
- package/src/contract/README.md +440 -0
- package/src/db/README.md +589 -0
- package/src/db/manager/README.md +500 -0
- package/src/db/schema/README.md +354 -0
- package/src/db/transaction/README.md +822 -0
- package/src/env/README.md +787 -0
- package/src/errors/README.md +429 -0
- package/src/event/README.md +789 -0
- package/src/job/README.md +613 -0
- package/src/logger/README.md +321 -0
- package/src/middleware/README.md +634 -0
- package/src/nextjs/README.md +688 -0
- package/src/route/README.md +763 -0
- package/src/security/README.md +100 -0
- package/src/server/README.md +704 -0
- package/dist/types-9oszaJqp.d.ts +0 -250
package/dist/nextjs/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Router, RouteDef } from '@spfn/core/route';
|
|
2
|
-
import { R as RequestInterceptor, a as ResponseInterceptor, I as InferRouteInput, b as InferRouteOutput, A as ApiConfig } from '../types-
|
|
3
|
-
export { C as CallOptions, c as CookieOptions, d as RouterInput, e as RouterOutput, S as SetCookie, f as StructuredInput } from '../types-
|
|
2
|
+
import { R as RequestInterceptor, a as ResponseInterceptor, I as InferRouteInput, b as InferRouteOutput, E as ExtractRoutes, A as ApiConfig } from '../types-CxhPH4s_.js';
|
|
3
|
+
export { C as CallOptions, c as CookieOptions, d as RouterInput, e as RouterOutput, S as SetCookie, f as StructuredInput } from '../types-CxhPH4s_.js';
|
|
4
4
|
import '@sinclair/typebox';
|
|
5
5
|
import '@spfn/core/errors';
|
|
6
6
|
|
|
@@ -57,6 +57,11 @@ type RouteClient<TRoute extends RouteDef<any, any>> = {
|
|
|
57
57
|
tags?: string[];
|
|
58
58
|
};
|
|
59
59
|
}): RouteClient<TRoute>;
|
|
60
|
+
/**
|
|
61
|
+
* Set this call's timeout in milliseconds, overriding the client-wide one.
|
|
62
|
+
* Throws a `TypeError` unless `ms` is finite, `> 0` and `<= 2147483647`.
|
|
63
|
+
*/
|
|
64
|
+
timeout(ms: number): RouteClient<TRoute>;
|
|
60
65
|
/**
|
|
61
66
|
* Set request interceptor
|
|
62
67
|
*/
|
|
@@ -80,11 +85,42 @@ type RouteClient<TRoute extends RouteDef<any, any>> = {
|
|
|
80
85
|
call: HasAnyRequiredFields<InferRouteInput<TRoute>> extends true ? (input: CleanStructuredInput<InferRouteInput<TRoute>>) => Promise<InferRouteOutput<TRoute>> : (input?: CleanStructuredInput<InferRouteInput<TRoute>>) => Promise<InferRouteOutput<TRoute>>;
|
|
81
86
|
};
|
|
82
87
|
/**
|
|
83
|
-
*
|
|
88
|
+
* One property per route in a flattened route record.
|
|
89
|
+
*
|
|
90
|
+
* A slot the flattening could not resolve to a route definition is `never`, as it was
|
|
91
|
+
* before nesting was flattened — a record whose values are neither routes nor routers
|
|
92
|
+
* names nothing callable.
|
|
84
93
|
*/
|
|
85
|
-
type
|
|
86
|
-
[K in keyof
|
|
94
|
+
type RouteClients<TRoutes> = {
|
|
95
|
+
[K in keyof TRoutes]: TRoutes[K] extends RouteDef<any, any, any> ? RouteClient<TRoutes[K]> : never;
|
|
87
96
|
};
|
|
97
|
+
/**
|
|
98
|
+
* Typed client for entire router
|
|
99
|
+
*
|
|
100
|
+
* One flat namespace, holding the same route names the server registers. A route
|
|
101
|
+
* declared inside a nested `defineRouter` is reached by its own key — `api.getThing`,
|
|
102
|
+
* never `api.group.getThing` — because that is the name `registerRoutes` mounts it
|
|
103
|
+
* under, the name the RPC proxy resolves, and the name `RouterOutput` takes. The group
|
|
104
|
+
* key is not a route and naming it is a compile error.
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* const appRouter = defineRouter({
|
|
109
|
+
* getRoot,
|
|
110
|
+
* users: defineRouter({ getUser }),
|
|
111
|
+
* });
|
|
112
|
+
*
|
|
113
|
+
* const api = createApi<typeof appRouter>();
|
|
114
|
+
*
|
|
115
|
+
* await api.getUser.call({ params: { id: '1' } }); // not api.users.getUser
|
|
116
|
+
* ```
|
|
117
|
+
*
|
|
118
|
+
* A name two branches both declare is left out of the namespace rather than resolved to
|
|
119
|
+
* one of them — the same collision `RouterOutput` refuses. Routes mounted with
|
|
120
|
+
* `.packages()` are deliberately absent: a package publishes its own route map and its
|
|
121
|
+
* own client (`authApi`, `cmsApi`), and that is what calls them.
|
|
122
|
+
*/
|
|
123
|
+
type Client<TRouter extends Router<any>> = RouteClients<ExtractRoutes<TRouter>>;
|
|
88
124
|
|
|
89
125
|
/**
|
|
90
126
|
* Create type-safe RPC client
|
|
@@ -106,15 +142,59 @@ type Client<TRouter extends Router<any>> = {
|
|
|
106
142
|
*/
|
|
107
143
|
declare function createApi<TRouter extends Router<any>>(config?: ApiConfig): Client<TRouter>;
|
|
108
144
|
|
|
145
|
+
/**
|
|
146
|
+
* CSRF token transport for the RPC client
|
|
147
|
+
*
|
|
148
|
+
* The Next.js proxy sets a readable (non-HttpOnly) cookie carrying an HMAC of
|
|
149
|
+
* the session's key id; this module mirrors it into a request header. The proxy
|
|
150
|
+
* never compares cookie against header — it recomputes the value from the
|
|
151
|
+
* session — so the cookie is transport only and reading it here is not a trust
|
|
152
|
+
* decision. See the CSRF section of the @spfn/auth README.
|
|
153
|
+
*/
|
|
154
|
+
/**
|
|
155
|
+
* Header the readable CSRF cookie is mirrored into.
|
|
156
|
+
*
|
|
157
|
+
* Must match CSRF_HEADER in @spfn/auth. It is duplicated rather than imported
|
|
158
|
+
* because @spfn/core cannot depend on @spfn/auth.
|
|
159
|
+
*/
|
|
160
|
+
declare const CSRF_HEADER = "x-spfn-csrf";
|
|
161
|
+
/**
|
|
162
|
+
* Collect the CSRF token candidates from cookie entries.
|
|
163
|
+
*
|
|
164
|
+
* Takes entries rather than a map because a name can legitimately appear twice:
|
|
165
|
+
* a sibling subdomain that tosses `spfn_csrf` for the parent domain leaves the
|
|
166
|
+
* browser holding two cookies of that name, and folding them into a map would
|
|
167
|
+
* throw away whichever the tossed one displaced — locking the user out of every
|
|
168
|
+
* mutation. Sending both keeps the real one in play, and the tossed one is inert
|
|
169
|
+
* because the proxy recomputes what it expects.
|
|
170
|
+
*
|
|
171
|
+
* @returns Header value (comma-separated), or undefined when no cookie exists
|
|
172
|
+
*/
|
|
173
|
+
declare function csrfHeaderValue(cookies: Iterable<[string, string]>): string | undefined;
|
|
174
|
+
/**
|
|
175
|
+
* Read the browser cookie jar as entries, duplicates preserved.
|
|
176
|
+
*
|
|
177
|
+
* Empty outside a browser (SSR reads the jar it forwards instead).
|
|
178
|
+
*/
|
|
179
|
+
declare function documentCookieEntries(): Array<[string, string]>;
|
|
180
|
+
|
|
109
181
|
/**
|
|
110
182
|
* Typed client error
|
|
183
|
+
*
|
|
184
|
+
* `errorType` tells apart why a call failed:
|
|
185
|
+
* - `'http'`: the server answered with a non-2xx status
|
|
186
|
+
* - `'network'`: the fetch or the body read failed (status 0)
|
|
187
|
+
* - `'timeout'`: the call's timeout elapsed before response headers arrived (status 408)
|
|
188
|
+
* - `'aborted'`: the caller's own signal aborted the call (status 0); `cause` is the signal's reason
|
|
111
189
|
*/
|
|
112
190
|
declare class ApiError extends Error {
|
|
113
191
|
readonly status: number;
|
|
114
192
|
readonly url: string;
|
|
115
193
|
readonly response?: unknown | undefined;
|
|
116
|
-
readonly errorType?: "http" | "network" | "timeout" | undefined;
|
|
117
|
-
constructor(message: string, status: number, url: string, response?: unknown | undefined, errorType?: "http" | "network" | "timeout" | undefined
|
|
194
|
+
readonly errorType?: "http" | "network" | "timeout" | "aborted" | undefined;
|
|
195
|
+
constructor(message: string, status: number, url: string, response?: unknown | undefined, errorType?: "http" | "network" | "timeout" | "aborted" | undefined, options?: {
|
|
196
|
+
cause?: unknown;
|
|
197
|
+
});
|
|
118
198
|
}
|
|
119
199
|
|
|
120
|
-
export { ApiConfig, ApiError, type Client, InferRouteInput, InferRouteOutput, RequestInterceptor, ResponseInterceptor, type RouteClient, createApi };
|
|
200
|
+
export { ApiConfig, ApiError, CSRF_HEADER, type Client, InferRouteInput, InferRouteOutput, RequestInterceptor, ResponseInterceptor, type RouteClient, createApi, csrfHeaderValue, documentCookieEntries };
|
package/dist/nextjs/index.js
CHANGED
|
@@ -69,8 +69,8 @@ function logThrowingDeserializedError(logger3, error) {
|
|
|
69
69
|
|
|
70
70
|
// src/nextjs/client/errors.ts
|
|
71
71
|
var ApiError = class extends Error {
|
|
72
|
-
constructor(message, status, url, response, errorType) {
|
|
73
|
-
super(message);
|
|
72
|
+
constructor(message, status, url, response, errorType, options) {
|
|
73
|
+
super(message, options);
|
|
74
74
|
this.status = status;
|
|
75
75
|
this.url = url;
|
|
76
76
|
this.response = response;
|
|
@@ -123,19 +123,45 @@ async function autoDetectServerCookies() {
|
|
|
123
123
|
return {};
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
|
-
|
|
126
|
+
function openAbortScope(callerSignal, timeout) {
|
|
127
127
|
const controller = new AbortController();
|
|
128
|
-
|
|
128
|
+
let cause;
|
|
129
|
+
const abort = (source, reason) => {
|
|
130
|
+
cause ??= source;
|
|
131
|
+
controller.abort(reason);
|
|
132
|
+
};
|
|
133
|
+
const onCallerAbort = () => abort("caller", callerSignal?.reason);
|
|
134
|
+
const timeoutId = setTimeout(() => abort("timeout"), timeout);
|
|
135
|
+
callerSignal?.addEventListener("abort", onCallerAbort, { once: true });
|
|
136
|
+
return {
|
|
137
|
+
signal: controller.signal,
|
|
138
|
+
cause: () => cause,
|
|
139
|
+
stopTimer: () => clearTimeout(timeoutId),
|
|
140
|
+
close: () => {
|
|
141
|
+
clearTimeout(timeoutId);
|
|
142
|
+
callerSignal?.removeEventListener("abort", onCallerAbort);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
async function fetchInAbortScope(url, init, timeout, customFetch = fetch) {
|
|
147
|
+
const callerSignal = init.signal ?? void 0;
|
|
148
|
+
if (callerSignal?.aborted) {
|
|
149
|
+
return { ok: false, error: callerSignal.reason, cause: "caller" };
|
|
150
|
+
}
|
|
151
|
+
const scope = openAbortScope(callerSignal, timeout);
|
|
129
152
|
try {
|
|
130
|
-
const response = await customFetch(url, {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
153
|
+
const response = await customFetch(url, { ...init, signal: scope.signal });
|
|
154
|
+
scope.stopTimer();
|
|
155
|
+
const body = await parseResponseBody(response);
|
|
156
|
+
if (scope.cause() === "caller") {
|
|
157
|
+
return { ok: false, error: callerSignal?.reason, cause: "caller" };
|
|
158
|
+
}
|
|
159
|
+
return { ok: true, response, body };
|
|
136
160
|
} catch (error) {
|
|
137
|
-
|
|
138
|
-
|
|
161
|
+
const cause = scope.cause();
|
|
162
|
+
return { ok: false, cause, error: cause === "caller" ? callerSignal?.reason : error };
|
|
163
|
+
} finally {
|
|
164
|
+
scope.close();
|
|
139
165
|
}
|
|
140
166
|
}
|
|
141
167
|
async function handleErrorResponse(response, body, fullUrl, errorRegistry, debug, logger3) {
|
|
@@ -180,7 +206,40 @@ async function handleErrorResponse(response, body, fullUrl, errorRegistry, debug
|
|
|
180
206
|
);
|
|
181
207
|
}
|
|
182
208
|
|
|
209
|
+
// src/nextjs/client/csrf.ts
|
|
210
|
+
var CSRF_HEADER = "x-spfn-csrf";
|
|
211
|
+
var CSRF_COOKIE_PATTERN = /^spfn_csrf(_\d+)?$/;
|
|
212
|
+
var HEADER_SAFE_VALUE = /^[!-~]+$/;
|
|
213
|
+
var MAX_CANDIDATES = 32;
|
|
214
|
+
function selectCandidates(values) {
|
|
215
|
+
const unique = Array.from(new Set(values));
|
|
216
|
+
if (unique.length <= MAX_CANDIDATES) {
|
|
217
|
+
return unique;
|
|
218
|
+
}
|
|
219
|
+
const half = MAX_CANDIDATES / 2;
|
|
220
|
+
return [...unique.slice(0, half), ...unique.slice(-half)];
|
|
221
|
+
}
|
|
222
|
+
function csrfHeaderValue(cookies) {
|
|
223
|
+
const values = Array.from(cookies).filter(([name, value]) => CSRF_COOKIE_PATTERN.test(name) && HEADER_SAFE_VALUE.test(value) && !value.includes(",")).map(([, value]) => value);
|
|
224
|
+
const candidates = selectCandidates(values);
|
|
225
|
+
return candidates.length > 0 ? candidates.join(",") : void 0;
|
|
226
|
+
}
|
|
227
|
+
function documentCookieEntries() {
|
|
228
|
+
if (typeof document === "undefined" || !document.cookie) {
|
|
229
|
+
return [];
|
|
230
|
+
}
|
|
231
|
+
const entries = [];
|
|
232
|
+
for (const pair of document.cookie.split(";")) {
|
|
233
|
+
const separator = pair.indexOf("=");
|
|
234
|
+
if (separator > 0) {
|
|
235
|
+
entries.push([pair.slice(0, separator).trim(), pair.slice(separator + 1).trim()]);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return entries;
|
|
239
|
+
}
|
|
240
|
+
|
|
183
241
|
// src/nextjs/client/builder.ts
|
|
242
|
+
var MAX_TIMEOUT_MS = 2147483647;
|
|
184
243
|
var RouteCallBuilder = class _RouteCallBuilder {
|
|
185
244
|
constructor(executor, routeName) {
|
|
186
245
|
this.executor = executor;
|
|
@@ -189,6 +248,7 @@ var RouteCallBuilder = class _RouteCallBuilder {
|
|
|
189
248
|
_headers;
|
|
190
249
|
_cookies;
|
|
191
250
|
_fetchOptions;
|
|
251
|
+
_timeout;
|
|
192
252
|
_onRequest;
|
|
193
253
|
_onResponse;
|
|
194
254
|
/**
|
|
@@ -202,6 +262,7 @@ var RouteCallBuilder = class _RouteCallBuilder {
|
|
|
202
262
|
builder._headers = this._headers;
|
|
203
263
|
builder._cookies = this._cookies;
|
|
204
264
|
builder._fetchOptions = this._fetchOptions;
|
|
265
|
+
builder._timeout = this._timeout;
|
|
205
266
|
builder._onRequest = this._onRequest;
|
|
206
267
|
builder._onResponse = this._onResponse;
|
|
207
268
|
return builder;
|
|
@@ -230,6 +291,20 @@ var RouteCallBuilder = class _RouteCallBuilder {
|
|
|
230
291
|
builder._fetchOptions = { ...this._fetchOptions, ...options };
|
|
231
292
|
return builder;
|
|
232
293
|
}
|
|
294
|
+
/**
|
|
295
|
+
* Set this call's timeout in milliseconds, overriding the client-wide one
|
|
296
|
+
*
|
|
297
|
+
* Throws a `TypeError`, before any request is made, unless `ms` is a finite number
|
|
298
|
+
* greater than 0 and at most 2147483647 (the largest delay `setTimeout` honours).
|
|
299
|
+
*/
|
|
300
|
+
timeout(ms) {
|
|
301
|
+
if (!Number.isFinite(ms) || ms <= 0 || ms > MAX_TIMEOUT_MS) {
|
|
302
|
+
throw new TypeError(`timeout must be a finite number of milliseconds in (0, ${MAX_TIMEOUT_MS}], got ${String(ms)}`);
|
|
303
|
+
}
|
|
304
|
+
const builder = this.clone();
|
|
305
|
+
builder._timeout = ms;
|
|
306
|
+
return builder;
|
|
307
|
+
}
|
|
233
308
|
/**
|
|
234
309
|
* Set request interceptor
|
|
235
310
|
*/
|
|
@@ -265,6 +340,9 @@ var RouteCallBuilder = class _RouteCallBuilder {
|
|
|
265
340
|
if (this._fetchOptions) {
|
|
266
341
|
options.fetchOptions = this._fetchOptions;
|
|
267
342
|
}
|
|
343
|
+
if (this._timeout !== void 0) {
|
|
344
|
+
options.timeout = this._timeout;
|
|
345
|
+
}
|
|
268
346
|
if (this._onRequest) {
|
|
269
347
|
options.onRequest = this._onRequest;
|
|
270
348
|
}
|
|
@@ -277,6 +355,28 @@ var RouteCallBuilder = class _RouteCallBuilder {
|
|
|
277
355
|
|
|
278
356
|
// src/nextjs/client/core.ts
|
|
279
357
|
var apiLogger = logger.child("@spfn/core:api-client");
|
|
358
|
+
function transportError(failure, site, timeout) {
|
|
359
|
+
if (failure.cause === "timeout") {
|
|
360
|
+
apiLogger.error("Request timeout", { ...site, timeout });
|
|
361
|
+
return new ApiError(`Request timeout after ${timeout}ms`, 408, site.url, void 0, "timeout");
|
|
362
|
+
}
|
|
363
|
+
if (failure.cause === "caller") {
|
|
364
|
+
apiLogger.debug("Request aborted by caller", site);
|
|
365
|
+
return new ApiError("Request aborted", 0, site.url, void 0, "aborted", { cause: failure.error });
|
|
366
|
+
}
|
|
367
|
+
const { error } = failure;
|
|
368
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
369
|
+
apiLogger.error("Request timeout", { ...site, timeout });
|
|
370
|
+
return new ApiError(`Request timeout after ${timeout}ms`, 408, site.url, void 0, "timeout");
|
|
371
|
+
}
|
|
372
|
+
const errorMessage = error instanceof Error ? error.message : "Network error";
|
|
373
|
+
apiLogger.error("Network error", {
|
|
374
|
+
...site,
|
|
375
|
+
error: errorMessage,
|
|
376
|
+
errorName: error instanceof Error ? error.name : "unknown"
|
|
377
|
+
});
|
|
378
|
+
return new ApiError(errorMessage, 0, site.url, void 0, "network");
|
|
379
|
+
}
|
|
280
380
|
function createApi(config = {}) {
|
|
281
381
|
const {
|
|
282
382
|
baseUrl = "/api/rpc",
|
|
@@ -335,6 +435,13 @@ function createApi(config = {}) {
|
|
|
335
435
|
if (Object.keys(cookiesToSend).length > 0) {
|
|
336
436
|
headers["Cookie"] = buildCookieHeader(cookiesToSend);
|
|
337
437
|
}
|
|
438
|
+
const csrfToken = csrfHeaderValue(
|
|
439
|
+
typeof window === "undefined" ? Object.entries(cookiesToSend) : documentCookieEntries()
|
|
440
|
+
);
|
|
441
|
+
const csrfSetByCaller = Object.keys(headers).some((name) => name.toLowerCase() === CSRF_HEADER);
|
|
442
|
+
if (csrfToken && !csrfSetByCaller) {
|
|
443
|
+
headers[CSRF_HEADER] = csrfToken;
|
|
444
|
+
}
|
|
338
445
|
if (debug && Object.keys(autoDetectedCookies).length > 0) {
|
|
339
446
|
const cookieArray = Object.entries(autoDetectedCookies).map(([name, value]) => ({ name, value }));
|
|
340
447
|
logCookieAutoDetection(apiLogger, cookieArray);
|
|
@@ -385,55 +492,24 @@ function createApi(config = {}) {
|
|
|
385
492
|
if (debug) {
|
|
386
493
|
logRequest(apiLogger, routeName, method, fullUrl, !!init.body);
|
|
387
494
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
} catch (error) {
|
|
407
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
408
|
-
apiLogger.error("Request timeout", {
|
|
409
|
-
route: routeName,
|
|
410
|
-
method,
|
|
411
|
-
url: fullUrl,
|
|
412
|
-
timeout
|
|
413
|
-
});
|
|
414
|
-
throw new ApiError(
|
|
415
|
-
`Request timeout after ${timeout}ms`,
|
|
416
|
-
408,
|
|
417
|
-
fullUrl,
|
|
418
|
-
void 0,
|
|
419
|
-
"timeout"
|
|
420
|
-
);
|
|
421
|
-
}
|
|
422
|
-
const errorMessage = error instanceof Error ? error.message : "Network error";
|
|
423
|
-
apiLogger.error("Network error", {
|
|
424
|
-
route: routeName,
|
|
425
|
-
method,
|
|
426
|
-
url: fullUrl,
|
|
427
|
-
error: errorMessage,
|
|
428
|
-
errorName: error instanceof Error ? error.name : "unknown"
|
|
429
|
-
});
|
|
430
|
-
throw new ApiError(
|
|
431
|
-
errorMessage,
|
|
432
|
-
0,
|
|
433
|
-
fullUrl,
|
|
434
|
-
void 0,
|
|
435
|
-
"network"
|
|
436
|
-
);
|
|
495
|
+
const appliedTimeout = options.timeout ?? timeout;
|
|
496
|
+
const fetched = await fetchInAbortScope(fullUrl, init, appliedTimeout, customFetch);
|
|
497
|
+
if (!fetched.ok) {
|
|
498
|
+
throw transportError(fetched, { route: routeName, method, url: fullUrl }, appliedTimeout);
|
|
499
|
+
}
|
|
500
|
+
let { response, body } = fetched;
|
|
501
|
+
if (globalOnResponse) {
|
|
502
|
+
const result = await globalOnResponse(response, body);
|
|
503
|
+
response = result.response;
|
|
504
|
+
body = result.body;
|
|
505
|
+
}
|
|
506
|
+
if (options.onResponse) {
|
|
507
|
+
const result = await options.onResponse(response, body);
|
|
508
|
+
response = result.response;
|
|
509
|
+
body = result.body;
|
|
510
|
+
}
|
|
511
|
+
if (debug) {
|
|
512
|
+
logResponse(apiLogger, routeName, response.status, !!body);
|
|
437
513
|
}
|
|
438
514
|
if (!response.ok) {
|
|
439
515
|
await handleErrorResponse(response, body, fullUrl, errorRegistry$1, debug, apiLogger);
|
|
@@ -457,6 +533,6 @@ function createApi(config = {}) {
|
|
|
457
533
|
return buildProxy();
|
|
458
534
|
}
|
|
459
535
|
|
|
460
|
-
export { ApiError, createApi };
|
|
536
|
+
export { ApiError, CSRF_HEADER, createApi, csrfHeaderValue, documentCookieEntries };
|
|
461
537
|
//# sourceMappingURL=index.js.map
|
|
462
538
|
//# sourceMappingURL=index.js.map
|