@route-forge/core 1.4.0 → 2.0.0
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 +10 -6
- package/dist/codegen.d.cts +1 -1
- package/dist/codegen.d.ts +1 -1
- package/dist/index.cjs +137 -112
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -5
- package/dist/index.d.ts +16 -5
- package/dist/index.js +137 -112
- package/dist/index.js.map +1 -1
- package/dist/route-forge.global.js +137 -112
- package/dist/route-forge.global.js.map +1 -1
- package/dist/route-forge.global.min.js +2 -2
- package/dist/{types-BFlrOTrN.d.cts → types-BvLdl02f.d.cts} +6 -17
- package/dist/{types-BFlrOTrN.d.ts → types-BvLdl02f.d.ts} +6 -17
- package/package.json +1 -1
|
@@ -17,9 +17,18 @@ var RouteForge = (function (exports) {
|
|
|
17
17
|
var RouteCache = class {
|
|
18
18
|
constructor(opts) {
|
|
19
19
|
this.memory = /* @__PURE__ */ new Map();
|
|
20
|
+
/** 其他 tab 修改 storage 时失效对应镜像(storage 事件:自己的写不触发,自己的写经 set/del 已同步) */
|
|
21
|
+
this.onStorageEvent = (e) => {
|
|
22
|
+
if (!e.key) return;
|
|
23
|
+
if (!e.key.startsWith(KEY_PREFIX)) return;
|
|
24
|
+
this.memory.delete(e.key.slice(KEY_PREFIX.length));
|
|
25
|
+
};
|
|
20
26
|
this.storage = opts.storage;
|
|
21
27
|
this.fallbackTtl = opts.ttl;
|
|
22
28
|
this.backend = pickStorage(opts.storage);
|
|
29
|
+
if (this.backend && typeof globalThis.addEventListener === "function") {
|
|
30
|
+
globalThis.addEventListener("storage", this.onStorageEvent);
|
|
31
|
+
}
|
|
23
32
|
}
|
|
24
33
|
key(level) {
|
|
25
34
|
return `${KEY_PREFIX}${level}`;
|
|
@@ -28,6 +37,8 @@ var RouteForge = (function (exports) {
|
|
|
28
37
|
if (this.storage === "memory" || !this.backend) {
|
|
29
38
|
return this.getFromMemory(level);
|
|
30
39
|
}
|
|
40
|
+
const mirrored = this.getFromMemory(level);
|
|
41
|
+
if (mirrored) return mirrored;
|
|
31
42
|
const raw = this.backend.getItem(this.key(level));
|
|
32
43
|
if (raw) {
|
|
33
44
|
try {
|
|
@@ -36,12 +47,13 @@ var RouteForge = (function (exports) {
|
|
|
36
47
|
this.del(level);
|
|
37
48
|
return void 0;
|
|
38
49
|
}
|
|
50
|
+
this.memory.set(level, entry);
|
|
39
51
|
return entry;
|
|
40
52
|
} catch {
|
|
41
53
|
return void 0;
|
|
42
54
|
}
|
|
43
55
|
}
|
|
44
|
-
return
|
|
56
|
+
return void 0;
|
|
45
57
|
}
|
|
46
58
|
getFromMemory(level) {
|
|
47
59
|
const entry = this.memory.get(level);
|
|
@@ -65,14 +77,13 @@ var RouteForge = (function (exports) {
|
|
|
65
77
|
ttl,
|
|
66
78
|
cachedAt: Date.now()
|
|
67
79
|
};
|
|
80
|
+
this.memory.set(resp.level, entry);
|
|
68
81
|
if (this.storage === "memory" || !this.backend) {
|
|
69
|
-
this.memory.set(resp.level, entry);
|
|
70
82
|
return;
|
|
71
83
|
}
|
|
72
84
|
try {
|
|
73
85
|
this.backend.setItem(this.key(resp.level), JSON.stringify(entry));
|
|
74
86
|
} catch {
|
|
75
|
-
this.memory.set(resp.level, entry);
|
|
76
87
|
}
|
|
77
88
|
}
|
|
78
89
|
del(level) {
|
|
@@ -252,14 +263,14 @@ var RouteForge = (function (exports) {
|
|
|
252
263
|
return new InterceptorManagerImpl();
|
|
253
264
|
}
|
|
254
265
|
|
|
255
|
-
// src/adapters/
|
|
256
|
-
function
|
|
257
|
-
if (
|
|
258
|
-
return typeof FormData !== "undefined" && body instanceof FormData || typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams || typeof Blob !== "undefined" && body instanceof Blob || typeof ArrayBuffer !== "undefined" && (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) || typeof ReadableStream !== "undefined" && body instanceof ReadableStream;
|
|
259
|
-
}
|
|
260
|
-
function isAbortError(err) {
|
|
266
|
+
// src/adapters/fetch-core.ts
|
|
267
|
+
function isAbortError(err, signal) {
|
|
268
|
+
if (signal?.aborted) return true;
|
|
261
269
|
const e = err;
|
|
262
|
-
|
|
270
|
+
if (!e) return false;
|
|
271
|
+
if (e.name === "AbortError") return true;
|
|
272
|
+
if (e.code === "ERR_CANCELED") return true;
|
|
273
|
+
return false;
|
|
263
274
|
}
|
|
264
275
|
function combineSignals(...signals) {
|
|
265
276
|
const valid = signals.filter((s) => !!s);
|
|
@@ -278,82 +289,89 @@ var RouteForge = (function (exports) {
|
|
|
278
289
|
}
|
|
279
290
|
return controller.signal;
|
|
280
291
|
}
|
|
281
|
-
function
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
)
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
292
|
+
function isPassthroughBody(body) {
|
|
293
|
+
if (body === null) return false;
|
|
294
|
+
return typeof FormData !== "undefined" && body instanceof FormData || typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams || typeof Blob !== "undefined" && body instanceof Blob || typeof ArrayBuffer !== "undefined" && (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) || typeof ReadableStream !== "undefined" && body instanceof ReadableStream;
|
|
295
|
+
}
|
|
296
|
+
async function rawFetch(config) {
|
|
297
|
+
const signal = combineSignals(
|
|
298
|
+
config.signal,
|
|
299
|
+
config.timeout && config.timeout > 0 ? AbortSignal.timeout(config.timeout) : void 0
|
|
300
|
+
);
|
|
301
|
+
let url = config.url;
|
|
302
|
+
if (config.paramsSerializer && config.params) {
|
|
303
|
+
const qs = config.paramsSerializer(config.params);
|
|
304
|
+
if (qs) {
|
|
305
|
+
url = url.includes("?") ? `${url}&${qs}` : `${url}?${qs}`;
|
|
295
306
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
307
|
+
}
|
|
308
|
+
const headers = new Headers(config.headers);
|
|
309
|
+
const fetchInit = {
|
|
310
|
+
method: config.method,
|
|
311
|
+
headers
|
|
312
|
+
};
|
|
313
|
+
if (signal) fetchInit.signal = signal;
|
|
314
|
+
if (config.body !== void 0 && !["GET", "HEAD"].includes(config.method.toUpperCase())) {
|
|
315
|
+
if (typeof config.body === "string" || isPassthroughBody(config.body)) {
|
|
316
|
+
fetchInit.body = config.body;
|
|
317
|
+
} else {
|
|
318
|
+
fetchInit.body = JSON.stringify(config.body);
|
|
319
|
+
if (!headers.has("Content-Type")) {
|
|
320
|
+
headers.set("Content-Type", "application/json");
|
|
310
321
|
}
|
|
311
322
|
}
|
|
312
|
-
|
|
323
|
+
}
|
|
324
|
+
let res;
|
|
325
|
+
try {
|
|
326
|
+
res = await fetch(url, fetchInit);
|
|
327
|
+
} catch (e) {
|
|
328
|
+
if (isAbortError(e)) throw e;
|
|
329
|
+
throw new NetworkError(
|
|
330
|
+
e instanceof Error ? e.message : String(e),
|
|
331
|
+
config.route,
|
|
332
|
+
config.level,
|
|
333
|
+
e
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
const text = await res.text();
|
|
337
|
+
let data = text;
|
|
338
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
339
|
+
if (contentType.includes("application/json")) {
|
|
313
340
|
try {
|
|
314
|
-
|
|
315
|
-
} catch
|
|
316
|
-
if (isAbortError(e)) throw e;
|
|
317
|
-
throw new NetworkError(
|
|
318
|
-
e instanceof Error ? e.message : String(e),
|
|
319
|
-
config.route,
|
|
320
|
-
config.level,
|
|
321
|
-
e
|
|
322
|
-
);
|
|
323
|
-
}
|
|
324
|
-
const text = await res.text();
|
|
325
|
-
let data = text;
|
|
326
|
-
const contentType = res.headers.get("content-type") ?? "";
|
|
327
|
-
if (contentType.includes("application/json")) {
|
|
328
|
-
try {
|
|
329
|
-
data = JSON.parse(text);
|
|
330
|
-
} catch {
|
|
331
|
-
}
|
|
341
|
+
data = JSON.parse(text);
|
|
342
|
+
} catch {
|
|
332
343
|
}
|
|
333
|
-
|
|
344
|
+
}
|
|
345
|
+
const responseData = {
|
|
346
|
+
route: config.route,
|
|
347
|
+
level: config.level,
|
|
348
|
+
method: config.method,
|
|
349
|
+
url,
|
|
350
|
+
status: res.status,
|
|
351
|
+
headers: res.headers,
|
|
352
|
+
data,
|
|
353
|
+
config
|
|
354
|
+
};
|
|
355
|
+
if (res.status >= 200 && res.status < 300) {
|
|
356
|
+
return responseData;
|
|
357
|
+
}
|
|
358
|
+
throw new HTTPError(
|
|
359
|
+
`HTTP ${res.status} for route "${config.route}" (${config.method} ${url})`,
|
|
360
|
+
{
|
|
334
361
|
route: config.route,
|
|
335
362
|
level: config.level,
|
|
336
|
-
method: config.method,
|
|
337
|
-
url,
|
|
338
363
|
status: res.status,
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
config
|
|
342
|
-
};
|
|
343
|
-
if (res.status >= 200 && res.status < 300) {
|
|
344
|
-
return responseData;
|
|
364
|
+
url,
|
|
365
|
+
method: config.method
|
|
345
366
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
}
|
|
355
|
-
);
|
|
356
|
-
}
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// src/adapters/builtin-http.ts
|
|
371
|
+
function createBuiltinHttp(forgeInterceptors) {
|
|
372
|
+
const requestMgr = forgeInterceptors?.request ?? createInterceptorManager();
|
|
373
|
+
const responseMgr = forgeInterceptors?.response ?? createInterceptorManager();
|
|
374
|
+
const requestRaw = rawFetch;
|
|
357
375
|
async function request(config) {
|
|
358
376
|
const finalConfig = await runRequestInterceptors(requestMgr, config);
|
|
359
377
|
const source = Promise.resolve(finalConfig).then(requestRaw);
|
|
@@ -588,17 +606,12 @@ var RouteForge = (function (exports) {
|
|
|
588
606
|
let effectiveUrlPrefix = "";
|
|
589
607
|
let summaryUnassigned;
|
|
590
608
|
let backendHasUnassignedLevel = false;
|
|
591
|
-
const
|
|
609
|
+
const fetchSummary = async () => {
|
|
592
610
|
try {
|
|
593
|
-
const
|
|
594
|
-
const
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
`[route-forge] summary endpoint ${summaryUrl} unreachable (HTTP ${resp.status}); falling back to explicit options`
|
|
598
|
-
);
|
|
599
|
-
return null;
|
|
600
|
-
}
|
|
601
|
-
return await resp.json();
|
|
611
|
+
const base = baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL;
|
|
612
|
+
const ep = explicitEndpoint.startsWith("/") ? explicitEndpoint : `/${explicitEndpoint}`;
|
|
613
|
+
const data = await fetchMeta("__forge__.summary", `${base}${ep}`);
|
|
614
|
+
return data;
|
|
602
615
|
} catch (e) {
|
|
603
616
|
if (explicitLevels && explicitLevels.length > 0) {
|
|
604
617
|
console.warn(
|
|
@@ -608,8 +621,11 @@ var RouteForge = (function (exports) {
|
|
|
608
621
|
}
|
|
609
622
|
throw new UnknownLevelError("(auto-discovery)");
|
|
610
623
|
}
|
|
611
|
-
}
|
|
612
|
-
|
|
624
|
+
};
|
|
625
|
+
let summaryPromise;
|
|
626
|
+
const summaryWaiters = [];
|
|
627
|
+
const whenSummary = () => summaryPromise ?? new Promise((resolve) => summaryWaiters.push(resolve));
|
|
628
|
+
const autoDiscoveryPromise = whenSummary().then((summary) => {
|
|
613
629
|
if (summary === null) {
|
|
614
630
|
return;
|
|
615
631
|
}
|
|
@@ -663,8 +679,12 @@ var RouteForge = (function (exports) {
|
|
|
663
679
|
});
|
|
664
680
|
let autoDiscoveryCompleted = false;
|
|
665
681
|
let resolveReady;
|
|
666
|
-
|
|
682
|
+
let rejectReady;
|
|
683
|
+
const readyPromise = new Promise((resolve, reject) => {
|
|
667
684
|
resolveReady = resolve;
|
|
685
|
+
rejectReady = reject;
|
|
686
|
+
});
|
|
687
|
+
readyPromise.catch(() => {
|
|
668
688
|
});
|
|
669
689
|
const cacheTtl = cacheOpts.ttl ?? DEFAULT_CACHE_TTL;
|
|
670
690
|
const cacheStorage = cacheOpts.storage ?? "memory";
|
|
@@ -695,6 +715,10 @@ var RouteForge = (function (exports) {
|
|
|
695
715
|
adapter,
|
|
696
716
|
forgeInterceptors: { request: requestInterceptors, response: responseInterceptors }
|
|
697
717
|
});
|
|
718
|
+
Promise.resolve().then(() => {
|
|
719
|
+
summaryPromise = fetchSummary();
|
|
720
|
+
for (const resolve of summaryWaiters) resolve(summaryPromise);
|
|
721
|
+
});
|
|
698
722
|
let adapterResolved = false;
|
|
699
723
|
let adapterObj = null;
|
|
700
724
|
async function ensureAdapter() {
|
|
@@ -730,19 +754,19 @@ var RouteForge = (function (exports) {
|
|
|
730
754
|
const ep = effectiveEndpoint.startsWith("/") ? effectiveEndpoint : `/${effectiveEndpoint}`;
|
|
731
755
|
return `${base}${ep}/${encodeURIComponent(level)}`;
|
|
732
756
|
}
|
|
733
|
-
async function
|
|
757
|
+
async function fetchMeta(routeTag, url, level = "") {
|
|
734
758
|
const adp = await ensureAdapter();
|
|
735
759
|
const config = {
|
|
736
|
-
route:
|
|
760
|
+
route: routeTag,
|
|
737
761
|
level,
|
|
738
762
|
method: "GET",
|
|
739
|
-
url
|
|
763
|
+
url,
|
|
740
764
|
headers: { Accept: "application/json" },
|
|
741
765
|
params: {},
|
|
742
766
|
timeout,
|
|
743
767
|
meta: {
|
|
744
|
-
name:
|
|
745
|
-
uri:
|
|
768
|
+
name: routeTag,
|
|
769
|
+
uri: url,
|
|
746
770
|
methods: ["GET"],
|
|
747
771
|
parameters: [],
|
|
748
772
|
level
|
|
@@ -752,12 +776,14 @@ var RouteForge = (function (exports) {
|
|
|
752
776
|
const resp = await doRawRequest(config);
|
|
753
777
|
if (!resp || resp.status < 200 || resp.status >= 300) {
|
|
754
778
|
throw new HTTPError(
|
|
755
|
-
`Failed to
|
|
756
|
-
{ level, status: resp?.status, url
|
|
779
|
+
`Failed to fetch "${routeTag}": HTTP ${resp?.status}`,
|
|
780
|
+
{ level, status: resp?.status, url, method: "GET" }
|
|
757
781
|
);
|
|
758
782
|
}
|
|
759
|
-
|
|
760
|
-
|
|
783
|
+
return resp.data;
|
|
784
|
+
}
|
|
785
|
+
async function fetchLevel(level) {
|
|
786
|
+
return await fetchMeta(`__forge__.load.${level}`, buildUrl(level), level);
|
|
761
787
|
}
|
|
762
788
|
async function loadOne(level) {
|
|
763
789
|
if (autoDiscoveryError) throw autoDiscoveryError;
|
|
@@ -929,7 +955,7 @@ var RouteForge = (function (exports) {
|
|
|
929
955
|
},
|
|
930
956
|
(err) => {
|
|
931
957
|
if (err instanceof ForgeError) throw err;
|
|
932
|
-
if (
|
|
958
|
+
if (isAbortError(err, signal)) {
|
|
933
959
|
throw new RequestAbortedError(meta.name, meta.level, err);
|
|
934
960
|
}
|
|
935
961
|
throw new NetworkError(
|
|
@@ -998,15 +1024,22 @@ var RouteForge = (function (exports) {
|
|
|
998
1024
|
}
|
|
999
1025
|
void autoDiscoveryPromise.then(() => {
|
|
1000
1026
|
autoDiscoveryCompleted = true;
|
|
1001
|
-
options.onSummaryReady?.();
|
|
1002
1027
|
if (effectiveEager.length > 0) {
|
|
1003
|
-
return Promise.
|
|
1004
|
-
|
|
1028
|
+
return Promise.allSettled(effectiveEager.map((lvl) => load(lvl))).then((results) => {
|
|
1029
|
+
results.forEach((r, i) => {
|
|
1030
|
+
if (r.status === "rejected") {
|
|
1031
|
+
console.error(
|
|
1032
|
+
`[route-forge] eager load failed for level "${effectiveEager[i]}":`,
|
|
1033
|
+
r.reason
|
|
1034
|
+
);
|
|
1035
|
+
}
|
|
1036
|
+
});
|
|
1005
1037
|
});
|
|
1006
1038
|
}
|
|
1007
1039
|
}).then(() => {
|
|
1008
1040
|
resolveReady(forgeInstance);
|
|
1009
|
-
}).catch(() => {
|
|
1041
|
+
}).catch((e) => {
|
|
1042
|
+
rejectReady(e);
|
|
1010
1043
|
});
|
|
1011
1044
|
function ready(onFulfilled, onRejected) {
|
|
1012
1045
|
if (onFulfilled) {
|
|
@@ -1152,14 +1185,6 @@ var RouteForge = (function (exports) {
|
|
|
1152
1185
|
}
|
|
1153
1186
|
return { pathParams, query, body, headers, timeout: perCallTimeout };
|
|
1154
1187
|
}
|
|
1155
|
-
function isAbortError2(err, signal) {
|
|
1156
|
-
if (signal?.aborted) return true;
|
|
1157
|
-
const e = err;
|
|
1158
|
-
if (!e) return false;
|
|
1159
|
-
if (e.name === "AbortError") return true;
|
|
1160
|
-
if (e.code === "ERR_CANCELED") return true;
|
|
1161
|
-
return false;
|
|
1162
|
-
}
|
|
1163
1188
|
|
|
1164
1189
|
exports.AdapterNotFoundError = AdapterNotFoundError;
|
|
1165
1190
|
exports.ForgeError = ForgeError;
|