@cedvict/http-guardian 0.0.1-next.6 → 0.0.1-next.8
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/CHANGELOG.md +23 -0
- package/LICENSE +21 -1
- package/README.md +76 -0
- package/dist/aliases.d.ts +35 -0
- package/dist/aliases.d.ts.map +1 -0
- package/dist/auth/authConfig.d.ts +91 -0
- package/dist/auth/authConfig.d.ts.map +1 -0
- package/dist/cache/inFlight.d.ts +10 -0
- package/dist/cache/inFlight.d.ts.map +1 -0
- package/dist/cache/key.d.ts +10 -0
- package/dist/cache/key.d.ts.map +1 -0
- package/dist/cache/memoryCache.d.ts +16 -0
- package/dist/cache/memoryCache.d.ts.map +1 -0
- package/dist/cache/types.d.ts +13 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/client/errors.d.ts +29 -0
- package/dist/client/errors.d.ts.map +1 -0
- package/dist/client/httpClient.d.ts +13 -0
- package/dist/client/httpClient.d.ts.map +1 -0
- package/dist/client/types.d.ts +84 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/guards/cookieSafeRefreshGuard.d.ts +40 -0
- package/dist/guards/cookieSafeRefreshGuard.d.ts.map +1 -0
- package/dist/guards/instrumentGuard.d.ts +12 -0
- package/dist/guards/instrumentGuard.d.ts.map +1 -0
- package/dist/guards/retryGuard.d.ts +12 -0
- package/dist/guards/retryGuard.d.ts.map +1 -0
- package/dist/guards/types.d.ts +3 -0
- package/dist/guards/types.d.ts.map +1 -0
- package/dist/guards/unauthorizedGuard.d.ts +19 -0
- package/dist/guards/unauthorizedGuard.d.ts.map +1 -0
- package/dist/index.cjs +1413 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +22 -322
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +643 -63
- package/dist/index.js.map +1 -1
- package/dist/internal/authGuard.d.ts +4 -0
- package/dist/internal/authGuard.d.ts.map +1 -0
- package/dist/internal/compose.d.ts +7 -0
- package/dist/internal/compose.d.ts.map +1 -0
- package/dist/internal/context.d.ts +31 -0
- package/dist/internal/context.d.ts.map +1 -0
- package/dist/internal/headersPolyfill.d.ts +25 -0
- package/dist/internal/headersPolyfill.d.ts.map +1 -0
- package/dist/internal/stableStringify.d.ts +2 -0
- package/dist/internal/stableStringify.d.ts.map +1 -0
- package/dist/internal/url.d.ts +3 -0
- package/dist/internal/url.d.ts.map +1 -0
- package/dist/notify/defaults.d.ts +9 -0
- package/dist/notify/defaults.d.ts.map +1 -0
- package/dist/notify/types.d.ts +33 -0
- package/dist/notify/types.d.ts.map +1 -0
- package/dist/parsing/presets.d.ts +15 -0
- package/dist/parsing/presets.d.ts.map +1 -0
- package/dist/parsing/schemaAdapter.d.ts +18 -0
- package/dist/parsing/schemaAdapter.d.ts.map +1 -0
- package/dist/parsing/shapeParser.d.ts +8 -0
- package/dist/parsing/shapeParser.d.ts.map +1 -0
- package/dist/plugins/types.d.ts +22 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/presets/presetBuilder.d.ts +181 -0
- package/dist/presets/presetBuilder.d.ts.map +1 -0
- package/dist/publicTypes.d.ts +12 -0
- package/dist/publicTypes.d.ts.map +1 -0
- package/package.json +10 -5
package/dist/index.js
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
// src/internal/compose.ts
|
|
2
2
|
function composeGuards(guards, terminal) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return dispatch(0, ctx);
|
|
13
|
-
};
|
|
3
|
+
if (!guards.length) return terminal;
|
|
4
|
+
return (ctx) => dispatch(0, ctx);
|
|
5
|
+
function dispatch(i, c) {
|
|
6
|
+
const guard = guards[i];
|
|
7
|
+
if (!guard) return terminal(c);
|
|
8
|
+
return Promise.resolve(
|
|
9
|
+
guard(c, (nextCtx) => dispatch(i + 1, nextCtx ?? c))
|
|
10
|
+
);
|
|
11
|
+
}
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
// src/internal/url.ts
|
|
@@ -36,6 +34,34 @@ function sanitizeHeaderValue(v) {
|
|
|
36
34
|
if (/[\r\n]/.test(v)) return null;
|
|
37
35
|
return v;
|
|
38
36
|
}
|
|
37
|
+
function base64Encode(input) {
|
|
38
|
+
if (typeof globalThis.btoa === "function") return globalThis.btoa(input);
|
|
39
|
+
const B = globalThis.Buffer;
|
|
40
|
+
if (typeof B?.from === "function") return B.from(input, "utf8").toString("base64");
|
|
41
|
+
throw new Error("No base64 encoder available in this runtime");
|
|
42
|
+
}
|
|
43
|
+
function isUnsafeMethod(m) {
|
|
44
|
+
const u = m.toUpperCase();
|
|
45
|
+
return u !== "GET" && u !== "HEAD" && u !== "OPTIONS";
|
|
46
|
+
}
|
|
47
|
+
function sameOrigin(url, baseOrigin) {
|
|
48
|
+
if (!baseOrigin) return true;
|
|
49
|
+
try {
|
|
50
|
+
return new URL(url).origin === baseOrigin;
|
|
51
|
+
} catch {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function isAllowedOrigin(url, baseOrigin, allowed) {
|
|
56
|
+
if (!allowed) return sameOrigin(url, baseOrigin);
|
|
57
|
+
if (typeof allowed === "function") return !!allowed(url);
|
|
58
|
+
try {
|
|
59
|
+
const origin = new URL(url).origin;
|
|
60
|
+
return allowed.includes(origin);
|
|
61
|
+
} catch {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
39
65
|
function authGuard(auth) {
|
|
40
66
|
return async (ctx, next) => {
|
|
41
67
|
if (ctx.noAuth) return next(ctx);
|
|
@@ -43,6 +69,9 @@ function authGuard(auth) {
|
|
|
43
69
|
if (auth.mode === "bearer") {
|
|
44
70
|
const token = await auth.getToken();
|
|
45
71
|
if (token) {
|
|
72
|
+
if (!isAllowedOrigin(ctx.url, ctx.baseOrigin, auth.allowedOrigins)) {
|
|
73
|
+
return next(ctx);
|
|
74
|
+
}
|
|
46
75
|
const headerName = auth.headerName ?? "Authorization";
|
|
47
76
|
const prefix = auth.prefix ?? "Bearer";
|
|
48
77
|
const safe = sanitizeHeaderValue(`${prefix} ${token}`);
|
|
@@ -50,8 +79,36 @@ function authGuard(auth) {
|
|
|
50
79
|
}
|
|
51
80
|
return next(ctx);
|
|
52
81
|
}
|
|
82
|
+
if (auth.mode === "basic") {
|
|
83
|
+
const cred = await auth.getCredentials();
|
|
84
|
+
if (cred) {
|
|
85
|
+
if (!isAllowedOrigin(ctx.url, ctx.baseOrigin, auth.allowedOrigins)) {
|
|
86
|
+
return next(ctx);
|
|
87
|
+
}
|
|
88
|
+
const headerName = auth.headerName ?? "Authorization";
|
|
89
|
+
const prefix = auth.prefix ?? "Basic";
|
|
90
|
+
const raw = typeof cred === "string" ? cred : `${cred.username}:${cred.password}`;
|
|
91
|
+
const safe = sanitizeHeaderValue(`${prefix} ${base64Encode(raw)}`);
|
|
92
|
+
if (safe) ctx.headers.set(headerName, safe);
|
|
93
|
+
}
|
|
94
|
+
return next(ctx);
|
|
95
|
+
}
|
|
96
|
+
if (auth.mode === "apiKey") {
|
|
97
|
+
const key = await auth.getKey();
|
|
98
|
+
if (key) {
|
|
99
|
+
if (!isAllowedOrigin(ctx.url, ctx.baseOrigin, auth.allowedOrigins)) {
|
|
100
|
+
return next(ctx);
|
|
101
|
+
}
|
|
102
|
+
const headerName = auth.headerName ?? "X-API-Key";
|
|
103
|
+
const prefix = auth.prefix ?? "";
|
|
104
|
+
const value = prefix ? `${prefix} ${key}` : key;
|
|
105
|
+
const safe = sanitizeHeaderValue(value);
|
|
106
|
+
if (safe) ctx.headers.set(headerName, safe);
|
|
107
|
+
}
|
|
108
|
+
return next(ctx);
|
|
109
|
+
}
|
|
53
110
|
ctx.credentials = auth.credentials ?? "include";
|
|
54
|
-
if (auth.csrf) {
|
|
111
|
+
if (auth.csrf && isUnsafeMethod(ctx.method)) {
|
|
55
112
|
const csrf = await auth.csrf.getToken();
|
|
56
113
|
if (csrf) ctx.headers.set(auth.csrf.headerName, csrf);
|
|
57
114
|
}
|
|
@@ -59,6 +116,84 @@ function authGuard(auth) {
|
|
|
59
116
|
};
|
|
60
117
|
}
|
|
61
118
|
|
|
119
|
+
// src/internal/headersPolyfill.ts
|
|
120
|
+
function norm(name) {
|
|
121
|
+
return String(name).toLowerCase();
|
|
122
|
+
}
|
|
123
|
+
var HeadersPolyfill = class {
|
|
124
|
+
map = /* @__PURE__ */ new Map();
|
|
125
|
+
constructor(init) {
|
|
126
|
+
if (!init) return;
|
|
127
|
+
if (typeof init.forEach === "function" && typeof init.get === "function") {
|
|
128
|
+
init.forEach((v, k) => this.set(k, v));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (Symbol.iterator in Object(init)) {
|
|
132
|
+
for (const [k, v] of init) this.append(k, v);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
for (const [k, v] of Object.entries(init)) {
|
|
136
|
+
this.set(k, String(v));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
get(name) {
|
|
140
|
+
const hit = this.map.get(norm(name));
|
|
141
|
+
return hit ? hit.value : null;
|
|
142
|
+
}
|
|
143
|
+
has(name) {
|
|
144
|
+
return this.map.has(norm(name));
|
|
145
|
+
}
|
|
146
|
+
set(name, value) {
|
|
147
|
+
this.map.set(norm(name), { name, value: String(value) });
|
|
148
|
+
}
|
|
149
|
+
append(name, value) {
|
|
150
|
+
const key = norm(name);
|
|
151
|
+
const prev = this.map.get(key);
|
|
152
|
+
if (!prev) {
|
|
153
|
+
this.map.set(key, { name, value: String(value) });
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
this.map.set(key, { name: prev.name, value: `${prev.value}, ${String(value)}` });
|
|
157
|
+
}
|
|
158
|
+
delete(name) {
|
|
159
|
+
this.map.delete(norm(name));
|
|
160
|
+
}
|
|
161
|
+
forEach(cb) {
|
|
162
|
+
for (const { name, value } of this.map.values()) cb(value, name);
|
|
163
|
+
}
|
|
164
|
+
entries() {
|
|
165
|
+
const it = this.map.values();
|
|
166
|
+
return {
|
|
167
|
+
[Symbol.iterator]() {
|
|
168
|
+
return this;
|
|
169
|
+
},
|
|
170
|
+
next() {
|
|
171
|
+
const n = it.next();
|
|
172
|
+
if (n.done) return { done: true, value: void 0 };
|
|
173
|
+
return { done: false, value: [n.value.name, n.value.value] };
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/** Convert to HeadersInit that any fetch can consume. */
|
|
178
|
+
toObject() {
|
|
179
|
+
const out = {};
|
|
180
|
+
for (const { name, value } of this.map.values()) out[name] = value;
|
|
181
|
+
return out;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
function createHeaders(init) {
|
|
185
|
+
if (typeof globalThis.Headers === "function") {
|
|
186
|
+
return new globalThis.Headers(init);
|
|
187
|
+
}
|
|
188
|
+
return new HeadersPolyfill(init);
|
|
189
|
+
}
|
|
190
|
+
function toFetchHeaders(headers) {
|
|
191
|
+
if (typeof globalThis.Headers === "function" && headers instanceof globalThis.Headers) {
|
|
192
|
+
return headers;
|
|
193
|
+
}
|
|
194
|
+
return headers.toObject();
|
|
195
|
+
}
|
|
196
|
+
|
|
62
197
|
// src/internal/stableStringify.ts
|
|
63
198
|
function stableStringify(value) {
|
|
64
199
|
return JSON.stringify(sortValue(value));
|
|
@@ -175,21 +310,49 @@ function normalizeFetch(f) {
|
|
|
175
310
|
const bound = f.bind ? f.bind(globalThis) : f;
|
|
176
311
|
return ((input, init) => bound(input, init));
|
|
177
312
|
}
|
|
313
|
+
function getDefaultFetch() {
|
|
314
|
+
if (typeof globalThis.fetch === "function") return globalThis.fetch;
|
|
315
|
+
throw new Error(
|
|
316
|
+
"No global fetch detected. Provide a fetch implementation via createHttpClient({ fetch }) or run in an environment that supports fetch (Node >= 18 / modern browsers)."
|
|
317
|
+
);
|
|
318
|
+
}
|
|
178
319
|
var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
179
|
-
function createHttpClient(
|
|
180
|
-
const
|
|
181
|
-
|
|
320
|
+
function createHttpClient(options) {
|
|
321
|
+
const draft = { ...options };
|
|
322
|
+
if (draft.plugins?.length) {
|
|
323
|
+
const seen = /* @__PURE__ */ new Set();
|
|
324
|
+
for (const p of draft.plugins) {
|
|
325
|
+
if (!p || !p.name || typeof p.apply !== "function") continue;
|
|
326
|
+
if (seen.has(p.name)) continue;
|
|
327
|
+
seen.add(p.name);
|
|
328
|
+
p.apply(draft);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
const resolvedFetch = (() => {
|
|
332
|
+
if (draft.fetch) return normalizeFetch(draft.fetch);
|
|
333
|
+
let lastRef = null;
|
|
334
|
+
let lastBound = null;
|
|
335
|
+
return ((input, init) => {
|
|
336
|
+
const cur = getDefaultFetch();
|
|
337
|
+
if (cur !== lastRef || !lastBound) {
|
|
338
|
+
lastRef = cur;
|
|
339
|
+
lastBound = normalizeFetch(cur);
|
|
340
|
+
}
|
|
341
|
+
return lastBound(input, init);
|
|
342
|
+
});
|
|
343
|
+
})();
|
|
344
|
+
const cache = draft.cache;
|
|
182
345
|
const inFlight = new InFlight();
|
|
183
|
-
const defaultNotifier =
|
|
184
|
-
const shouldNotify =
|
|
185
|
-
const baseGuards = [authGuard(
|
|
346
|
+
const defaultNotifier = draft.notifier ?? consoleNotifier;
|
|
347
|
+
const shouldNotify = draft.defaults?.shouldNotify ?? ((r) => !r.ok);
|
|
348
|
+
const baseGuards = [authGuard(draft.auth), ...draft.guards ?? []];
|
|
186
349
|
async function terminal(ctx) {
|
|
187
350
|
const controller = ctx.timeoutMs ? new AbortController() : void 0;
|
|
188
351
|
const timeout = ctx.timeoutMs ? setTimeout(() => controller?.abort(new TimeoutError()), ctx.timeoutMs) : void 0;
|
|
189
352
|
try {
|
|
190
353
|
const init = {
|
|
191
354
|
method: ctx.method,
|
|
192
|
-
headers: ctx.headers,
|
|
355
|
+
headers: toFetchHeaders(ctx.headers),
|
|
193
356
|
...ctx.body !== void 0 ? { body: ctx.body } : {},
|
|
194
357
|
...ctx.signal ? { signal: controller ? anySignal([ctx.signal, controller.signal]) : ctx.signal } : controller ? { signal: controller.signal } : {},
|
|
195
358
|
...ctx.credentials !== void 0 ? { credentials: ctx.credentials } : {},
|
|
@@ -209,9 +372,9 @@ function createHttpClient(opts) {
|
|
|
209
372
|
}
|
|
210
373
|
const pipeline = composeGuards(baseGuards, terminal);
|
|
211
374
|
async function request(method, path, ro) {
|
|
212
|
-
const requestUrl = withQuery(joinUrl(
|
|
213
|
-
const headers =
|
|
214
|
-
if (
|
|
375
|
+
const requestUrl = withQuery(joinUrl(draft.baseUrl, path), ro?.query);
|
|
376
|
+
const headers = createHeaders();
|
|
377
|
+
if (draft.defaults?.headers) for (const [k, v] of Object.entries(draft.defaults.headers)) headers.set(k, v);
|
|
215
378
|
if (ro?.headers) {
|
|
216
379
|
for (const [k, v] of Object.entries(ro.headers)) if (v !== void 0) headers.set(k, v);
|
|
217
380
|
}
|
|
@@ -229,19 +392,31 @@ function createHttpClient(opts) {
|
|
|
229
392
|
} else {
|
|
230
393
|
if (!headers.has("accept")) headers.set("accept", "application/json");
|
|
231
394
|
}
|
|
232
|
-
const timeoutMs = ro?.timeoutMs ??
|
|
395
|
+
const timeoutMs = ro?.timeoutMs ?? draft.defaults?.timeoutMs;
|
|
233
396
|
const notifier = ro?.notifier ?? defaultNotifier;
|
|
397
|
+
const emit = (event) => {
|
|
398
|
+
const redact = notifier.redact;
|
|
399
|
+
const n = notifier.notify?.bind(notifier) ?? defaultNotifier.notify.bind(defaultNotifier);
|
|
400
|
+
return n(redact ? redact(event) : event);
|
|
401
|
+
};
|
|
234
402
|
const cacheOpts = ro?.cache;
|
|
235
403
|
const wantsCache = method === "GET" && !!cache && !!cacheOpts;
|
|
236
404
|
const dedupe = cacheOpts?.dedupe ?? true;
|
|
237
405
|
const canDedupeWrite = method !== "GET" && !!ro?.idempotencyKey;
|
|
238
|
-
const inflightKey = (wantsCache || canDedupeWrite) && dedupe ? makeCacheKey({
|
|
406
|
+
const inflightKey = (wantsCache || canDedupeWrite) && dedupe ? makeCacheKey({
|
|
407
|
+
method,
|
|
408
|
+
url: requestUrl,
|
|
409
|
+
headers,
|
|
410
|
+
...method === "GET" ? {} : { body: bodyForKey },
|
|
411
|
+
...ro?.idempotencyKey !== void 0 ? { idempotencyKey: ro.idempotencyKey } : {},
|
|
412
|
+
...cacheOpts?.key !== void 0 ? { keyOverride: cacheOpts.key } : {}
|
|
413
|
+
}) : void 0;
|
|
239
414
|
if (inflightKey) {
|
|
240
415
|
const existing = inFlight.get(inflightKey);
|
|
241
416
|
if (existing) {
|
|
242
417
|
try {
|
|
243
418
|
const stored = await existing;
|
|
244
|
-
return asClientResult(stored, requestUrl,
|
|
419
|
+
return asClientResult(stored, requestUrl, draft, ro, notifier, shouldNotify, emit);
|
|
245
420
|
} catch {
|
|
246
421
|
}
|
|
247
422
|
}
|
|
@@ -263,7 +438,7 @@ function createHttpClient(opts) {
|
|
|
263
438
|
}
|
|
264
439
|
}
|
|
265
440
|
const res = await fetchWithRedirects({
|
|
266
|
-
opts,
|
|
441
|
+
opts: draft,
|
|
267
442
|
resolvedFetch,
|
|
268
443
|
pipeline,
|
|
269
444
|
method,
|
|
@@ -278,13 +453,17 @@ function createHttpClient(opts) {
|
|
|
278
453
|
const envelope = { kind: "network", url: res.url || requestUrl, status: res.status, headers: res.headers, raw };
|
|
279
454
|
if (wantsCache && cacheOpts && res.ok) {
|
|
280
455
|
const key = inflightKey;
|
|
281
|
-
cache.set(key, {
|
|
456
|
+
cache.set(key, {
|
|
457
|
+
expiresAt: Date.now() + cacheOpts.ttlMs,
|
|
458
|
+
value: raw,
|
|
459
|
+
...cacheOpts.tags ? { tags: cacheOpts.tags } : {}
|
|
460
|
+
});
|
|
282
461
|
}
|
|
283
462
|
return envelope;
|
|
284
463
|
async function refreshInBackground(key) {
|
|
285
464
|
try {
|
|
286
465
|
const res2 = await fetchWithRedirects({
|
|
287
|
-
opts,
|
|
466
|
+
opts: draft,
|
|
288
467
|
resolvedFetch,
|
|
289
468
|
pipeline,
|
|
290
469
|
method,
|
|
@@ -297,7 +476,11 @@ function createHttpClient(opts) {
|
|
|
297
476
|
});
|
|
298
477
|
if (!res2.ok) return;
|
|
299
478
|
const raw2 = await decodeResponse(res2);
|
|
300
|
-
cache.set(key, {
|
|
479
|
+
cache.set(key, {
|
|
480
|
+
expiresAt: Date.now() + cacheOpts.ttlMs,
|
|
481
|
+
value: raw2,
|
|
482
|
+
...cacheOpts.tags ? { tags: cacheOpts.tags } : {}
|
|
483
|
+
});
|
|
301
484
|
} catch {
|
|
302
485
|
}
|
|
303
486
|
}
|
|
@@ -305,13 +488,13 @@ function createHttpClient(opts) {
|
|
|
305
488
|
if (inflightKey) inFlight.set(inflightKey, promise);
|
|
306
489
|
try {
|
|
307
490
|
const stored = await promise;
|
|
308
|
-
return asClientResult(stored, requestUrl,
|
|
491
|
+
return asClientResult(stored, requestUrl, draft, ro, notifier, shouldNotify, emit);
|
|
309
492
|
} catch (e) {
|
|
310
493
|
const err = e instanceof TimeoutError ? e : new NetworkError(
|
|
311
494
|
isIllegalInvocation(e) ? `Network request failed. ${ILLEGAL_INVOCATION_HINT}` : "Network request failed",
|
|
312
495
|
e
|
|
313
496
|
);
|
|
314
|
-
if (shouldNotify({ ok: false, status: 0 }))
|
|
497
|
+
if (shouldNotify({ ok: false, status: 0 })) emit({ type: "network-error", level: "error", title: "Network error", message: err.message, url: requestUrl });
|
|
315
498
|
return { ok: false, status: 0, headers: new Headers(), errors: [{ message: err.message, details: e }], raw: null, url: requestUrl };
|
|
316
499
|
}
|
|
317
500
|
}
|
|
@@ -343,7 +526,19 @@ async function fetchWithRedirects(args) {
|
|
|
343
526
|
);
|
|
344
527
|
if (!REDIRECT_STATUSES.has(res.status)) return res;
|
|
345
528
|
const loc = res.headers.get("location");
|
|
346
|
-
if (!loc)
|
|
529
|
+
if (!loc) {
|
|
530
|
+
return args.pipeline(
|
|
531
|
+
makeCtx(
|
|
532
|
+
{
|
|
533
|
+
...args,
|
|
534
|
+
url: currentUrl,
|
|
535
|
+
method,
|
|
536
|
+
...body !== void 0 ? { body } : {}
|
|
537
|
+
},
|
|
538
|
+
"follow"
|
|
539
|
+
)
|
|
540
|
+
);
|
|
541
|
+
}
|
|
347
542
|
const nextUrl = new URL(loc, currentUrl).toString();
|
|
348
543
|
const decision = policy.onRedirect?.({ fromUrl: currentUrl, toUrl: nextUrl, status: res.status, hop, method });
|
|
349
544
|
if (decision?.action === "deny") throw new RedirectError(decision.reason ?? "Redirect denied by policy", currentUrl, nextUrl);
|
|
@@ -363,18 +558,38 @@ async function fetchWithRedirects(args) {
|
|
|
363
558
|
}
|
|
364
559
|
function stripAuthOnCrossOriginRedirect(opts, initialUrl, toUrl, headers) {
|
|
365
560
|
try {
|
|
366
|
-
if (opts.auth.mode !== "bearer") return;
|
|
367
561
|
const initialOrigin = new URL(initialUrl).origin;
|
|
368
562
|
const toOrigin = new URL(toUrl).origin;
|
|
369
|
-
if (initialOrigin
|
|
563
|
+
if (initialOrigin === toOrigin) return;
|
|
564
|
+
if (opts.auth.mode === "bearer") {
|
|
370
565
|
const headerName = opts.auth.headerName ?? "Authorization";
|
|
371
566
|
headers.delete(headerName);
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
if (opts.auth.mode === "basic") {
|
|
570
|
+
const headerName = opts.auth.headerName ?? "Authorization";
|
|
571
|
+
headers.delete(headerName);
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
if (opts.auth.mode === "apiKey") {
|
|
575
|
+
const headerName = opts.auth.headerName ?? "X-API-Key";
|
|
576
|
+
headers.delete(headerName);
|
|
577
|
+
return;
|
|
372
578
|
}
|
|
373
579
|
} catch {
|
|
374
580
|
}
|
|
375
581
|
}
|
|
376
582
|
function makeCtx(args, redirect) {
|
|
583
|
+
const baseOrigin = (() => {
|
|
584
|
+
try {
|
|
585
|
+
return new URL(args.opts.baseUrl).origin;
|
|
586
|
+
} catch {
|
|
587
|
+
return "";
|
|
588
|
+
}
|
|
589
|
+
})();
|
|
377
590
|
return {
|
|
591
|
+
baseUrl: args.opts.baseUrl,
|
|
592
|
+
baseOrigin,
|
|
378
593
|
method: args.method,
|
|
379
594
|
url: args.url,
|
|
380
595
|
headers: args.headers,
|
|
@@ -404,10 +619,10 @@ async function decodeResponse(res) {
|
|
|
404
619
|
throw new ParseError("Failed to read response body", void 0, e);
|
|
405
620
|
}
|
|
406
621
|
}
|
|
407
|
-
function asClientResult(envelope, requestUrl, opts, ro, notifier, shouldNotify) {
|
|
622
|
+
function asClientResult(envelope, requestUrl, opts, ro, notifier, shouldNotify, emit) {
|
|
408
623
|
if (envelope?.kind === "cache-miss") {
|
|
409
624
|
const errors2 = [{ message: "Cache miss" }];
|
|
410
|
-
if (shouldNotify({ ok: false, status: 0 }))
|
|
625
|
+
if (shouldNotify({ ok: false, status: 0 })) emit({ type: "http-error", level: "warning", title: "Cache", message: "Cache miss", status: 0, errors: errors2, url: requestUrl });
|
|
411
626
|
return { ok: false, status: 0, headers: new Headers(), errors: errors2, raw: envelope.raw, url: requestUrl };
|
|
412
627
|
}
|
|
413
628
|
const status = envelope.status ?? 0;
|
|
@@ -422,17 +637,24 @@ function asClientResult(envelope, requestUrl, opts, ro, notifier, shouldNotify)
|
|
|
422
637
|
return { ok: true, status, headers: resHeaders, data, raw, url: finalUrl };
|
|
423
638
|
} catch (e) {
|
|
424
639
|
const msg2 = e instanceof Error ? e.message : "Schema parse failed";
|
|
425
|
-
if (shouldNotify({ ok: false, status }))
|
|
640
|
+
if (shouldNotify({ ok: false, status })) emit({ type: "parse-error", level: "error", title: "Parse error", message: msg2, url: finalUrl });
|
|
426
641
|
return { ok: false, status, headers: resHeaders, errors: [{ message: msg2, details: e }], raw, url: finalUrl };
|
|
427
642
|
}
|
|
428
643
|
}
|
|
429
644
|
const errors = opts.parser.getErrors(raw, status);
|
|
430
645
|
const msg = errors[0]?.message ?? (status ? `HTTP ${status}` : "Request failed");
|
|
431
|
-
if (shouldNotify({ ok: false, status }))
|
|
646
|
+
if (shouldNotify({ ok: false, status })) emit({ type: "http-error", level: status >= 500 ? "error" : "warning", title: "Request failed", message: msg, status, errors, url: finalUrl });
|
|
432
647
|
return { ok: false, status, headers: resHeaders, errors, raw, url: finalUrl };
|
|
433
648
|
}
|
|
434
649
|
function anySignal(signals) {
|
|
435
650
|
const valid = signals.filter(Boolean);
|
|
651
|
+
const any = AbortSignal.any;
|
|
652
|
+
if (any) {
|
|
653
|
+
try {
|
|
654
|
+
return any(valid);
|
|
655
|
+
} catch {
|
|
656
|
+
}
|
|
657
|
+
}
|
|
436
658
|
const controller = new AbortController();
|
|
437
659
|
const onAbort = () => controller.abort();
|
|
438
660
|
for (const s of valid) {
|
|
@@ -448,7 +670,8 @@ function bearerAuth(getToken, opts) {
|
|
|
448
670
|
mode: "bearer",
|
|
449
671
|
getToken,
|
|
450
672
|
...opts?.headerName !== void 0 ? { headerName: opts.headerName } : {},
|
|
451
|
-
...opts?.prefix !== void 0 ? { prefix: opts.prefix } : {}
|
|
673
|
+
...opts?.prefix !== void 0 ? { prefix: opts.prefix } : {},
|
|
674
|
+
...opts?.allowedOrigins !== void 0 ? { allowedOrigins: opts.allowedOrigins } : {}
|
|
452
675
|
};
|
|
453
676
|
}
|
|
454
677
|
function cookieAuth(opts) {
|
|
@@ -458,6 +681,24 @@ function cookieAuth(opts) {
|
|
|
458
681
|
...opts?.csrf !== void 0 ? { csrf: opts.csrf } : {}
|
|
459
682
|
};
|
|
460
683
|
}
|
|
684
|
+
function basicAuth(getCredentials, opts) {
|
|
685
|
+
return {
|
|
686
|
+
mode: "basic",
|
|
687
|
+
getCredentials,
|
|
688
|
+
...opts?.headerName !== void 0 ? { headerName: opts.headerName } : {},
|
|
689
|
+
...opts?.prefix !== void 0 ? { prefix: opts.prefix } : {},
|
|
690
|
+
...opts?.allowedOrigins !== void 0 ? { allowedOrigins: opts.allowedOrigins } : {}
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
function apiKeyAuth(getKey, opts) {
|
|
694
|
+
return {
|
|
695
|
+
mode: "apiKey",
|
|
696
|
+
getKey,
|
|
697
|
+
...opts?.headerName !== void 0 ? { headerName: opts.headerName } : {},
|
|
698
|
+
...opts?.prefix !== void 0 ? { prefix: opts.prefix } : {},
|
|
699
|
+
...opts?.allowedOrigins !== void 0 ? { allowedOrigins: opts.allowedOrigins } : {}
|
|
700
|
+
};
|
|
701
|
+
}
|
|
461
702
|
function noAuth() {
|
|
462
703
|
return { mode: "none" };
|
|
463
704
|
}
|
|
@@ -497,8 +738,7 @@ function isReplayableBody(body) {
|
|
|
497
738
|
}
|
|
498
739
|
function normalizePath(url) {
|
|
499
740
|
try {
|
|
500
|
-
|
|
501
|
-
return u.pathname;
|
|
741
|
+
return new URL(url).pathname;
|
|
502
742
|
} catch {
|
|
503
743
|
const q = url.indexOf("?");
|
|
504
744
|
const h = url.indexOf("#");
|
|
@@ -515,6 +755,14 @@ function parseRetryAfterMs(headers) {
|
|
|
515
755
|
if (!Number.isNaN(date)) return Math.max(0, date - Date.now());
|
|
516
756
|
return null;
|
|
517
757
|
}
|
|
758
|
+
function isAbsoluteUrl(u) {
|
|
759
|
+
try {
|
|
760
|
+
void new URL(u);
|
|
761
|
+
return true;
|
|
762
|
+
} catch {
|
|
763
|
+
return false;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
518
766
|
function cookieSafeRefreshGuard(opts) {
|
|
519
767
|
const trigger = new Set(opts.triggerStatuses ?? [401, 419]);
|
|
520
768
|
const maxRetry = opts.maxRetry ?? 1;
|
|
@@ -527,38 +775,39 @@ function cookieSafeRefreshGuard(opts) {
|
|
|
527
775
|
const path = normalizePath(ctx.url);
|
|
528
776
|
if (opts.excludePaths?.includes(path)) return next(ctx);
|
|
529
777
|
if (ctx.noAuth) return next(ctx);
|
|
530
|
-
const refreshPathNorm = normalizePath(opts.refreshPath);
|
|
778
|
+
const refreshPathNorm = normalizePath(resolveRefreshUrl(ctx, opts.refreshPath));
|
|
531
779
|
if (path === refreshPathNorm) return next(ctx);
|
|
532
780
|
if (honorRetryAfter && refreshCooldownUntil > Date.now()) {
|
|
533
781
|
return next(ctx);
|
|
534
782
|
}
|
|
535
783
|
const res = await next(ctx);
|
|
536
784
|
if (!trigger.has(res.status)) return res;
|
|
537
|
-
if (opts.shouldRefresh && !opts.shouldRefresh(ctx, res.status))
|
|
538
|
-
return res;
|
|
539
|
-
}
|
|
785
|
+
if (opts.shouldRefresh && !opts.shouldRefresh(ctx, res.status)) return res;
|
|
540
786
|
const alreadyRetried = Number(anyCtx[RETRY_FLAG] ?? 0);
|
|
541
787
|
if (alreadyRetried >= maxRetry) return res;
|
|
542
|
-
if (!isReplayableBody(ctx.body))
|
|
543
|
-
return res;
|
|
544
|
-
}
|
|
788
|
+
if (!isReplayableBody(ctx.body)) return res;
|
|
545
789
|
const decision = await (refreshPromise ??= doRefresh(ctx, next).finally(() => {
|
|
546
790
|
refreshPromise = null;
|
|
547
791
|
}));
|
|
548
792
|
if (!decision.ok) {
|
|
549
|
-
opts.onRefreshFailed?.({
|
|
793
|
+
opts.onRefreshFailed?.({
|
|
794
|
+
url: ctx.url,
|
|
795
|
+
...decision.reason !== void 0 ? { reason: decision.reason } : {},
|
|
796
|
+
...decision.status !== void 0 ? { status: decision.status } : {}
|
|
797
|
+
});
|
|
550
798
|
return res;
|
|
551
799
|
}
|
|
552
800
|
opts.onRefreshSuccess?.({ url: ctx.url });
|
|
553
801
|
const retryCtx = Object.assign({}, ctx, { attempt: ctx.attempt + 1 });
|
|
554
802
|
retryCtx[RETRY_FLAG] = alreadyRetried + 1;
|
|
803
|
+
await applyCookieAuth(retryCtx);
|
|
555
804
|
return next(retryCtx);
|
|
556
805
|
};
|
|
557
806
|
async function doRefresh(originalCtx, next) {
|
|
558
807
|
if (honorRetryAfter && refreshCooldownUntil > Date.now()) {
|
|
559
808
|
return { ok: false, reason: "Refresh cooldown active" };
|
|
560
809
|
}
|
|
561
|
-
const refreshUrl = resolveRefreshUrl(originalCtx
|
|
810
|
+
const refreshUrl = resolveRefreshUrl(originalCtx, opts.refreshPath);
|
|
562
811
|
const refreshCtx = {
|
|
563
812
|
...originalCtx,
|
|
564
813
|
url: refreshUrl,
|
|
@@ -568,36 +817,177 @@ function cookieSafeRefreshGuard(opts) {
|
|
|
568
817
|
attempt: 0
|
|
569
818
|
};
|
|
570
819
|
refreshCtx[REFRESH_FLAG] = true;
|
|
820
|
+
refreshCtx[RETRY_FLAG] = 0;
|
|
821
|
+
await applyCookieAuth(refreshCtx);
|
|
571
822
|
try {
|
|
572
823
|
const res = await next(refreshCtx);
|
|
573
824
|
if (res.status === 429 && honorRetryAfter) {
|
|
574
825
|
const ms = parseRetryAfterMs(res.headers);
|
|
575
826
|
refreshCooldownUntil = Date.now() + (ms ?? 3e4);
|
|
576
|
-
return { ok: false, reason: "Refresh rate-limited (429)" };
|
|
827
|
+
return { ok: false, reason: "Refresh rate-limited (429)", status: 429 };
|
|
577
828
|
}
|
|
578
829
|
if (!res.ok) {
|
|
579
|
-
return { ok: false, reason: `Refresh failed (HTTP ${res.status})
|
|
830
|
+
return { ok: false, reason: `Refresh failed (HTTP ${res.status})`, status: res.status };
|
|
580
831
|
}
|
|
581
832
|
return { ok: true };
|
|
582
833
|
} catch (e) {
|
|
583
834
|
return { ok: false, reason: e instanceof Error ? e.message : "Refresh exception" };
|
|
584
835
|
}
|
|
585
836
|
}
|
|
586
|
-
function resolveRefreshUrl(
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
837
|
+
function resolveRefreshUrl(ctx, refreshPath) {
|
|
838
|
+
if (isAbsoluteUrl(refreshPath)) return refreshPath;
|
|
839
|
+
return joinUrl(ctx.baseUrl, refreshPath);
|
|
840
|
+
}
|
|
841
|
+
async function applyCookieAuth(ctx) {
|
|
842
|
+
if (ctx.noAuth) return;
|
|
843
|
+
const auth = ctx.auth;
|
|
844
|
+
if (!auth || auth.mode !== "cookie") return;
|
|
845
|
+
if (ctx.credentials === void 0) {
|
|
846
|
+
ctx.credentials = auth.credentials ?? "include";
|
|
847
|
+
}
|
|
848
|
+
if (auth.csrf) {
|
|
849
|
+
const hn = auth.csrf.headerName;
|
|
850
|
+
if (!ctx.headers.has(hn)) {
|
|
851
|
+
const t = await auth.csrf.getToken();
|
|
852
|
+
if (t != null && String(t) !== "") ctx.headers.set(hn, String(t));
|
|
596
853
|
}
|
|
597
854
|
}
|
|
598
855
|
}
|
|
599
856
|
}
|
|
600
857
|
|
|
858
|
+
// src/guards/unauthorizedGuard.ts
|
|
859
|
+
function normalizePath2(url) {
|
|
860
|
+
try {
|
|
861
|
+
return new URL(url).pathname;
|
|
862
|
+
} catch {
|
|
863
|
+
const q = url.indexOf("?");
|
|
864
|
+
const h = url.indexOf("#");
|
|
865
|
+
const cut = Math.min(q === -1 ? url.length : q, h === -1 ? url.length : h);
|
|
866
|
+
return url.slice(0, cut);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
function unauthorizedGuard(opts) {
|
|
870
|
+
const statuses = opts.statuses ?? [401, 419];
|
|
871
|
+
const ignoreNoAuth = opts.ignoreNoAuth ?? true;
|
|
872
|
+
const once = opts.once ?? true;
|
|
873
|
+
const cooldownMs = opts.cooldownMs ?? 250;
|
|
874
|
+
let locked = false;
|
|
875
|
+
let cooldownUntil = 0;
|
|
876
|
+
return async (ctx, next) => {
|
|
877
|
+
let res;
|
|
878
|
+
try {
|
|
879
|
+
res = await next(ctx);
|
|
880
|
+
} catch (e) {
|
|
881
|
+
throw e;
|
|
882
|
+
}
|
|
883
|
+
if (ignoreNoAuth && ctx.noAuth) return res;
|
|
884
|
+
const path = normalizePath2(ctx.url);
|
|
885
|
+
if (opts.excludePaths?.includes(path)) return res;
|
|
886
|
+
if (!statuses.includes(res.status)) return res;
|
|
887
|
+
if (opts.shouldHandle && !opts.shouldHandle(ctx, res.status)) return res;
|
|
888
|
+
const now = Date.now();
|
|
889
|
+
if (now < cooldownUntil) return res;
|
|
890
|
+
if (once) {
|
|
891
|
+
if (locked) return res;
|
|
892
|
+
locked = true;
|
|
893
|
+
}
|
|
894
|
+
try {
|
|
895
|
+
opts.onUnauthorized({ url: ctx.url, status: res.status });
|
|
896
|
+
} finally {
|
|
897
|
+
cooldownUntil = Date.now() + cooldownMs;
|
|
898
|
+
if (once) setTimeout(() => locked = false, cooldownMs);
|
|
899
|
+
}
|
|
900
|
+
return res;
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
// src/guards/instrumentGuard.ts
|
|
905
|
+
var REFRESH_FLAG2 = "__hg_is_refresh__";
|
|
906
|
+
var RETRY_FLAG2 = "__hg_refresh_retry__";
|
|
907
|
+
function safeUrl(u) {
|
|
908
|
+
try {
|
|
909
|
+
const url = new URL(u);
|
|
910
|
+
return url.toString();
|
|
911
|
+
} catch {
|
|
912
|
+
return u;
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
function nowMs() {
|
|
916
|
+
return typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
917
|
+
}
|
|
918
|
+
function headersToObject(h) {
|
|
919
|
+
if (!h) return {};
|
|
920
|
+
const out = {};
|
|
921
|
+
try {
|
|
922
|
+
h.forEach((v, k) => {
|
|
923
|
+
const key = String(k).toLowerCase();
|
|
924
|
+
if (key === "authorization" || key === "cookie" || key === "set-cookie" || key === "x-api-key" || key === "proxy-authorization") {
|
|
925
|
+
out[k] = "[REDACTED]";
|
|
926
|
+
} else {
|
|
927
|
+
out[k] = v;
|
|
928
|
+
}
|
|
929
|
+
});
|
|
930
|
+
} catch {
|
|
931
|
+
}
|
|
932
|
+
return out;
|
|
933
|
+
}
|
|
934
|
+
var __hg_req_seq = 0;
|
|
935
|
+
function instrumentGuard(opts, guard) {
|
|
936
|
+
const log = opts.log ?? ((line, data) => data !== void 0 ? console.log(line, data) : console.log(line));
|
|
937
|
+
return async (ctx, next) => {
|
|
938
|
+
const id = ++__hg_req_seq;
|
|
939
|
+
const t0 = nowMs();
|
|
940
|
+
const url = safeUrl(ctx.url);
|
|
941
|
+
const method = ctx.method ?? "GET";
|
|
942
|
+
if (opts.include && !opts.include.test(url)) {
|
|
943
|
+
return guard(ctx, next);
|
|
944
|
+
}
|
|
945
|
+
if (opts.exclude && opts.exclude.test(url)) {
|
|
946
|
+
return guard(ctx, next);
|
|
947
|
+
}
|
|
948
|
+
const anyCtx = ctx;
|
|
949
|
+
const attempt = ctx.attempt ?? 0;
|
|
950
|
+
const isRefresh = Boolean(anyCtx[REFRESH_FLAG2]);
|
|
951
|
+
const retryCount = Number(anyCtx[RETRY_FLAG2] ?? 0);
|
|
952
|
+
const noAuth2 = Boolean(ctx.noAuth);
|
|
953
|
+
const baseLine = `[HG][#${id}][${opts.name}]`;
|
|
954
|
+
log(`${baseLine} \u25B6 start`, {
|
|
955
|
+
method,
|
|
956
|
+
url,
|
|
957
|
+
attempt,
|
|
958
|
+
retryCount,
|
|
959
|
+
isRefresh,
|
|
960
|
+
noAuth: noAuth2,
|
|
961
|
+
baseUrl: ctx.baseUrl,
|
|
962
|
+
...opts.logInit ? {
|
|
963
|
+
credentials: ctx.credentials,
|
|
964
|
+
redirect: ctx.redirect,
|
|
965
|
+
headers: headersToObject(ctx.headers)
|
|
966
|
+
} : {},
|
|
967
|
+
...opts.stack ? { stack: new Error().stack } : {}
|
|
968
|
+
});
|
|
969
|
+
try {
|
|
970
|
+
const res = await guard(ctx, next);
|
|
971
|
+
const dt = Math.round(nowMs() - t0);
|
|
972
|
+
log(`${baseLine} \u25C0 end (${dt}ms)`, {
|
|
973
|
+
status: res.status,
|
|
974
|
+
ok: res.ok,
|
|
975
|
+
url: res.url || url,
|
|
976
|
+
redirected: res.redirected,
|
|
977
|
+
location: res.headers?.get?.("location") ?? null,
|
|
978
|
+
retryAfter: res.headers?.get?.("retry-after") ?? null
|
|
979
|
+
});
|
|
980
|
+
return res;
|
|
981
|
+
} catch (e) {
|
|
982
|
+
const dt = Math.round(nowMs() - t0);
|
|
983
|
+
log(`${baseLine} \u2716 throw (${dt}ms)`, {
|
|
984
|
+
error: e instanceof Error ? { name: e.name, message: e.message, stack: e.stack } : e
|
|
985
|
+
});
|
|
986
|
+
throw e;
|
|
987
|
+
}
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
|
|
601
991
|
// src/cache/memoryCache.ts
|
|
602
992
|
function memoryCache(opts) {
|
|
603
993
|
const max = opts?.maxEntries ?? 1e3;
|
|
@@ -794,6 +1184,196 @@ function createApiParserGraphQL(opts) {
|
|
|
794
1184
|
});
|
|
795
1185
|
}
|
|
796
1186
|
|
|
797
|
-
|
|
1187
|
+
// src/presets/presetBuilder.ts
|
|
1188
|
+
function createPresetBuilder(init) {
|
|
1189
|
+
const state = {
|
|
1190
|
+
baseUrl: init?.baseUrl ?? "",
|
|
1191
|
+
parser: init?.parser ?? createApiParserRestClassic(),
|
|
1192
|
+
auth: init?.auth ?? noAuth(),
|
|
1193
|
+
...init?.fetch ? { fetch: init.fetch } : {},
|
|
1194
|
+
...init?.notifier ? { notifier: init.notifier } : { notifier: consoleNotifier },
|
|
1195
|
+
guards: []
|
|
1196
|
+
};
|
|
1197
|
+
function ensureBaseUrl() {
|
|
1198
|
+
if (!state.baseUrl) throw new Error("presetBuilder: baseUrl is required");
|
|
1199
|
+
}
|
|
1200
|
+
const api = {
|
|
1201
|
+
/** Set / override baseUrl */
|
|
1202
|
+
baseUrl(baseUrl) {
|
|
1203
|
+
state.baseUrl = baseUrl;
|
|
1204
|
+
return api;
|
|
1205
|
+
},
|
|
1206
|
+
/** Set / override parser */
|
|
1207
|
+
parser(parser) {
|
|
1208
|
+
state.parser = parser;
|
|
1209
|
+
return api;
|
|
1210
|
+
},
|
|
1211
|
+
/** Set / override fetch */
|
|
1212
|
+
fetch(fetchImpl) {
|
|
1213
|
+
state.fetch = fetchImpl;
|
|
1214
|
+
return api;
|
|
1215
|
+
},
|
|
1216
|
+
/** Set / override notifier */
|
|
1217
|
+
notifier(notifier) {
|
|
1218
|
+
state.notifier = notifier;
|
|
1219
|
+
return api;
|
|
1220
|
+
},
|
|
1221
|
+
/** Add guard(s) (preserves order) */
|
|
1222
|
+
guards(...guards) {
|
|
1223
|
+
state.guards = [...state.guards ?? [], ...guards];
|
|
1224
|
+
return api;
|
|
1225
|
+
},
|
|
1226
|
+
/** Enable in-memory cache */
|
|
1227
|
+
memoryCache(opts) {
|
|
1228
|
+
state.cache = memoryCache(opts);
|
|
1229
|
+
return api;
|
|
1230
|
+
},
|
|
1231
|
+
/** Low-level cache assignment */
|
|
1232
|
+
cache(cache) {
|
|
1233
|
+
if (cache === void 0) {
|
|
1234
|
+
delete state.cache;
|
|
1235
|
+
} else {
|
|
1236
|
+
state.cache = cache;
|
|
1237
|
+
}
|
|
1238
|
+
return api;
|
|
1239
|
+
},
|
|
1240
|
+
/** Default headers / timeouts / notify policy */
|
|
1241
|
+
defaults(defaults) {
|
|
1242
|
+
state.defaults = { ...state.defaults ?? {}, ...defaults ?? {} };
|
|
1243
|
+
return api;
|
|
1244
|
+
},
|
|
1245
|
+
/** Redirect policy */
|
|
1246
|
+
redirects(redirects) {
|
|
1247
|
+
if (redirects === void 0) {
|
|
1248
|
+
delete state.redirects;
|
|
1249
|
+
} else {
|
|
1250
|
+
state.redirects = redirects;
|
|
1251
|
+
}
|
|
1252
|
+
return api;
|
|
1253
|
+
},
|
|
1254
|
+
/** Auth presets */
|
|
1255
|
+
auth(auth) {
|
|
1256
|
+
state.auth = auth;
|
|
1257
|
+
return api;
|
|
1258
|
+
},
|
|
1259
|
+
bearer(getToken, opts) {
|
|
1260
|
+
state.auth = bearerAuth(getToken, opts);
|
|
1261
|
+
return api;
|
|
1262
|
+
},
|
|
1263
|
+
cookie(opts) {
|
|
1264
|
+
state.auth = cookieAuth(opts);
|
|
1265
|
+
return api;
|
|
1266
|
+
},
|
|
1267
|
+
basic(getCred, opts) {
|
|
1268
|
+
state.auth = basicAuth(getCred, opts);
|
|
1269
|
+
return api;
|
|
1270
|
+
},
|
|
1271
|
+
apiKey(getKey, opts) {
|
|
1272
|
+
state.auth = apiKeyAuth(getKey, opts);
|
|
1273
|
+
return api;
|
|
1274
|
+
},
|
|
1275
|
+
none() {
|
|
1276
|
+
state.auth = noAuth();
|
|
1277
|
+
return api;
|
|
1278
|
+
},
|
|
1279
|
+
/**
|
|
1280
|
+
* Cookie refresh guard preset (only meaningful for cookie auth).
|
|
1281
|
+
* You can still add it manually via `.guards(...)`.
|
|
1282
|
+
*/
|
|
1283
|
+
cookieRefresh(opts) {
|
|
1284
|
+
state.guards = [...state.guards ?? [], cookieSafeRefreshGuard(opts)];
|
|
1285
|
+
return api;
|
|
1286
|
+
},
|
|
1287
|
+
/** Unauthorized handler preset (redirect/logout). */
|
|
1288
|
+
unauthorized(opts) {
|
|
1289
|
+
state.guards = [...state.guards ?? [], unauthorizedGuard(opts)];
|
|
1290
|
+
return api;
|
|
1291
|
+
},
|
|
1292
|
+
/** Returns the final HttpClientOptions */
|
|
1293
|
+
options() {
|
|
1294
|
+
ensureBaseUrl();
|
|
1295
|
+
return { ...state, guards: [...state.guards ?? []] };
|
|
1296
|
+
},
|
|
1297
|
+
/** Creates the http client */
|
|
1298
|
+
create() {
|
|
1299
|
+
ensureBaseUrl();
|
|
1300
|
+
return createHttpClient(api.options());
|
|
1301
|
+
}
|
|
1302
|
+
};
|
|
1303
|
+
return api;
|
|
1304
|
+
}
|
|
1305
|
+
function createSimpleClient(opts) {
|
|
1306
|
+
return createPresetBuilder(opts).create();
|
|
1307
|
+
}
|
|
1308
|
+
function createBearerClient(opts) {
|
|
1309
|
+
const bearerOpts = {
|
|
1310
|
+
...opts.headerName !== void 0 ? { headerName: opts.headerName } : {},
|
|
1311
|
+
...opts.prefix !== void 0 ? { prefix: opts.prefix } : {}
|
|
1312
|
+
};
|
|
1313
|
+
return createPresetBuilder({
|
|
1314
|
+
baseUrl: opts.baseUrl,
|
|
1315
|
+
...opts.parser ? { parser: opts.parser } : {},
|
|
1316
|
+
...opts.fetch ? { fetch: opts.fetch } : {},
|
|
1317
|
+
...opts.notifier ? { notifier: opts.notifier } : {}
|
|
1318
|
+
}).bearer(opts.getToken, Object.keys(bearerOpts).length ? bearerOpts : void 0).create();
|
|
1319
|
+
}
|
|
1320
|
+
function createCookieClient(opts) {
|
|
1321
|
+
const b = createPresetBuilder({
|
|
1322
|
+
baseUrl: opts.baseUrl,
|
|
1323
|
+
...opts.parser ? { parser: opts.parser } : {},
|
|
1324
|
+
...opts.fetch ? { fetch: opts.fetch } : {},
|
|
1325
|
+
...opts.notifier ? { notifier: opts.notifier } : {}
|
|
1326
|
+
}).cookie({
|
|
1327
|
+
...opts.credentials !== void 0 ? { credentials: opts.credentials } : {},
|
|
1328
|
+
...opts.csrf !== void 0 ? { csrf: opts.csrf } : {}
|
|
1329
|
+
});
|
|
1330
|
+
if (opts.refresh) b.cookieRefresh(opts.refresh);
|
|
1331
|
+
return b.create();
|
|
1332
|
+
}
|
|
1333
|
+
function createBasicClient(opts) {
|
|
1334
|
+
const basicOpts = {
|
|
1335
|
+
...opts.headerName !== void 0 ? { headerName: opts.headerName } : {},
|
|
1336
|
+
...opts.prefix !== void 0 ? { prefix: opts.prefix } : {}
|
|
1337
|
+
};
|
|
1338
|
+
return createPresetBuilder({
|
|
1339
|
+
baseUrl: opts.baseUrl,
|
|
1340
|
+
...opts.parser ? { parser: opts.parser } : {},
|
|
1341
|
+
...opts.fetch ? { fetch: opts.fetch } : {},
|
|
1342
|
+
...opts.notifier ? { notifier: opts.notifier } : {}
|
|
1343
|
+
}).basic(opts.getCredentials, Object.keys(basicOpts).length ? basicOpts : void 0).create();
|
|
1344
|
+
}
|
|
1345
|
+
function createApiKeyClient(opts) {
|
|
1346
|
+
const apiKeyOpts = {
|
|
1347
|
+
...opts.headerName !== void 0 ? { headerName: opts.headerName } : {},
|
|
1348
|
+
...opts.prefix !== void 0 ? { prefix: opts.prefix } : {}
|
|
1349
|
+
};
|
|
1350
|
+
return createPresetBuilder({
|
|
1351
|
+
baseUrl: opts.baseUrl,
|
|
1352
|
+
...opts.parser ? { parser: opts.parser } : {},
|
|
1353
|
+
...opts.fetch ? { fetch: opts.fetch } : {},
|
|
1354
|
+
...opts.notifier ? { notifier: opts.notifier } : {}
|
|
1355
|
+
}).apiKey(opts.getKey, Object.keys(apiKeyOpts).length ? apiKeyOpts : void 0).create();
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
// src/aliases.ts
|
|
1359
|
+
function createClient(opts) {
|
|
1360
|
+
const parser = opts.parser ?? createApiParserRestClassic();
|
|
1361
|
+
const auth = opts.auth ?? noAuth();
|
|
1362
|
+
const notifier = opts.notifier ?? consoleNotifier;
|
|
1363
|
+
const cfg = {
|
|
1364
|
+
baseUrl: opts.baseUrl,
|
|
1365
|
+
parser,
|
|
1366
|
+
auth,
|
|
1367
|
+
notifier,
|
|
1368
|
+
...opts.fetch ? { fetch: opts.fetch } : {},
|
|
1369
|
+
...opts.defaults ? { defaults: opts.defaults } : {},
|
|
1370
|
+
...opts.cache ? { cache: opts.cache } : {},
|
|
1371
|
+
...opts.redirects ? { redirects: opts.redirects } : {},
|
|
1372
|
+
...opts.guards ? { guards: opts.guards } : {}
|
|
1373
|
+
};
|
|
1374
|
+
return createHttpClient(cfg);
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
export { ILLEGAL_INVOCATION_HINT, NetworkError, ParseError, RedirectError, TimeoutError, alertNotifier, apiKeyAuth, basicAuth, bearerAuth, consoleNotifier, cookieAuth, cookieSafeRefreshGuard, createApiKeyClient, createApiParserGraphQL, createApiParserLaravel, createApiParserNest, createApiParserRestClassic, createBasicClient, createBearerClient, createClient, createCookieClient, createHttpClient, createPresetBuilder, createShapeParser, createSimpleClient, fromZod, instrumentGuard, memoryCache, noAuth, retryGuard, schema, tailwindAlertRenderer, unauthorizedGuard };
|
|
798
1378
|
//# sourceMappingURL=index.js.map
|
|
799
1379
|
//# sourceMappingURL=index.js.map
|