@route-forge/core 1.3.1 → 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 +50 -6
- package/dist/codegen.d.cts +1 -1
- package/dist/codegen.d.ts +1 -1
- package/dist/index.cjs +152 -123
- 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 +152 -123
- package/dist/index.js.map +1 -1
- package/dist/route-forge.global.js +152 -123
- package/dist/route-forge.global.js.map +1 -1
- package/dist/route-forge.global.min.js +2 -2
- package/dist/{types-Cd1c1OdJ.d.cts → types-BvLdl02f.d.cts} +13 -17
- package/dist/{types-Cd1c1OdJ.d.ts → types-BvLdl02f.d.ts} +13 -17
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as InterceptorManager, a as InterceptorHandler, C as CacheStorage, R as RouteMeta, L as LevelRoutesResponse, b as RouteForgeOptions, c as RouteForge } from './types-
|
|
2
|
-
export { A as AdapterOption, d as ApiCallParams, B as BoundForge, F as Fetcher, e as ForgeApiParams, f as ForgeApiResponse, g as ForgeRequest, h as ForgeRouteMap, i as ForgeRouteName, j as LoadingChangeCallback, k as LoadingChangeEvent, l as LoadingTracker, m as RequestConfig, n as ResponseData, S as SummaryResponse, U as UseForgeApiBoundCall, o as UseForgeApiBoundReturn, p as UseForgeApiCall, q as UseForgeApiReturn
|
|
1
|
+
import { I as InterceptorManager, a as InterceptorHandler, C as CacheStorage, R as RouteMeta, L as LevelRoutesResponse, b as RouteForgeOptions, c as RouteForge } from './types-BvLdl02f.js';
|
|
2
|
+
export { A as AdapterOption, d as ApiCallParams, B as BoundForge, F as Fetcher, e as ForgeApiParams, f as ForgeApiResponse, g as ForgeRequest, h as ForgeRouteMap, i as ForgeRouteName, j as LoadingChangeCallback, k as LoadingChangeEvent, l as LoadingTracker, m as RequestConfig, n as ResponseData, S as SummaryResponse, U as UseForgeApiBoundCall, o as UseForgeApiBoundReturn, p as UseForgeApiCall, q as UseForgeApiReturn } from './types-BvLdl02f.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* 拦截器管理器实现
|
|
@@ -45,6 +45,10 @@ declare function createInterceptorManager<TIn, TOut = TIn>(): InterceptorManager
|
|
|
45
45
|
* - 每层级独立条目,互不污染(cache key = `route-forge:${level}`)
|
|
46
46
|
* - TTL 优先用后端响应里的 cache 字段,本地 cache.ttl 仅作兜底
|
|
47
47
|
* - storage: 'memory' | 'sessionStorage' | 'localStorage'
|
|
48
|
+
* - storage 模式下维护内存镜像:首次读盘解析后驻留内存,后续 get 直接命中
|
|
49
|
+
* (读盘 + JSON.parse 整层路由表是同步阻塞操作,热路径重复执行代价高);
|
|
50
|
+
* 写操作(set/del/clear)同步更新镜像,并通过 storage 事件感知其他
|
|
51
|
+
* tab 的写入/失效,保证跨 tab 新鲜度与无镜像时一致
|
|
48
52
|
*/
|
|
49
53
|
|
|
50
54
|
interface CacheEntry {
|
|
@@ -58,6 +62,8 @@ declare class RouteCache {
|
|
|
58
62
|
private readonly fallbackTtl;
|
|
59
63
|
private readonly backend;
|
|
60
64
|
private readonly memory;
|
|
65
|
+
/** 其他 tab 修改 storage 时失效对应镜像(storage 事件:自己的写不触发,自己的写经 set/del 已同步) */
|
|
66
|
+
private readonly onStorageEvent;
|
|
61
67
|
constructor(opts: {
|
|
62
68
|
storage: CacheStorage;
|
|
63
69
|
ttl: number;
|
|
@@ -78,14 +84,19 @@ declare class RouteCache {
|
|
|
78
84
|
interface ForgeErrorContext {
|
|
79
85
|
[key: string]: unknown;
|
|
80
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Route Forge 错误码字面量联合。
|
|
89
|
+
* 用户侧 `switch (e.code)` 可获得穷尽检查(漏分支编译报错)。
|
|
90
|
+
*/
|
|
91
|
+
type ForgeErrorCode = 'RF_FE_001' | 'RF_FE_002' | 'RF_FE_003' | 'RF_FE_005' | 'RF_FE_006' | 'RF_FE_007' | 'RF_FE_008' | 'RF_FE_009' | 'RF_FE_010';
|
|
81
92
|
declare class ForgeError extends Error {
|
|
82
|
-
readonly code:
|
|
93
|
+
readonly code: ForgeErrorCode;
|
|
83
94
|
readonly route?: string;
|
|
84
95
|
readonly level?: string;
|
|
85
96
|
readonly context?: ForgeErrorContext;
|
|
86
97
|
readonly cause?: unknown;
|
|
87
98
|
constructor(message: string, opts: {
|
|
88
|
-
code:
|
|
99
|
+
code: ForgeErrorCode;
|
|
89
100
|
route?: string;
|
|
90
101
|
level?: string;
|
|
91
102
|
context?: ForgeErrorContext;
|
|
@@ -177,4 +188,4 @@ declare function resolveRouteName(forge: RouteResolver, level: string, prefix: s
|
|
|
177
188
|
*/
|
|
178
189
|
declare function resolveRouteNameSync(forge: RouteResolver, level: string, prefix: string, suffix: string, separator?: string): string;
|
|
179
190
|
|
|
180
|
-
export { AdapterNotFoundError, CacheStorage, ForgeError, HTTPError, InterceptorHandler, InterceptorManager, InterceptorManagerImpl, InvalidInterceptorReturnError, LevelRoutesResponse, MissingRouteParamError, NetworkError, RequestAbortedError, RouteCache, RouteForge, RouteForgeOptions, RouteMeta, type RouteResolver, UnknownLevelError, UnknownRouteError, createInterceptorManager, createRouteForge, resolveRouteName, resolveRouteNameSync };
|
|
191
|
+
export { AdapterNotFoundError, CacheStorage, ForgeError, type ForgeErrorCode, HTTPError, InterceptorHandler, InterceptorManager, InterceptorManagerImpl, InvalidInterceptorReturnError, LevelRoutesResponse, MissingRouteParamError, NetworkError, RequestAbortedError, RouteCache, RouteForge, RouteForgeOptions, RouteMeta, type RouteResolver, UnknownLevelError, UnknownRouteError, createInterceptorManager, createRouteForge, resolveRouteName, resolveRouteNameSync };
|
package/dist/index.js
CHANGED
|
@@ -14,9 +14,18 @@ function pickStorage(storage) {
|
|
|
14
14
|
var RouteCache = class {
|
|
15
15
|
constructor(opts) {
|
|
16
16
|
this.memory = /* @__PURE__ */ new Map();
|
|
17
|
+
/** 其他 tab 修改 storage 时失效对应镜像(storage 事件:自己的写不触发,自己的写经 set/del 已同步) */
|
|
18
|
+
this.onStorageEvent = (e) => {
|
|
19
|
+
if (!e.key) return;
|
|
20
|
+
if (!e.key.startsWith(KEY_PREFIX)) return;
|
|
21
|
+
this.memory.delete(e.key.slice(KEY_PREFIX.length));
|
|
22
|
+
};
|
|
17
23
|
this.storage = opts.storage;
|
|
18
24
|
this.fallbackTtl = opts.ttl;
|
|
19
25
|
this.backend = pickStorage(opts.storage);
|
|
26
|
+
if (this.backend && typeof globalThis.addEventListener === "function") {
|
|
27
|
+
globalThis.addEventListener("storage", this.onStorageEvent);
|
|
28
|
+
}
|
|
20
29
|
}
|
|
21
30
|
key(level) {
|
|
22
31
|
return `${KEY_PREFIX}${level}`;
|
|
@@ -25,6 +34,8 @@ var RouteCache = class {
|
|
|
25
34
|
if (this.storage === "memory" || !this.backend) {
|
|
26
35
|
return this.getFromMemory(level);
|
|
27
36
|
}
|
|
37
|
+
const mirrored = this.getFromMemory(level);
|
|
38
|
+
if (mirrored) return mirrored;
|
|
28
39
|
const raw = this.backend.getItem(this.key(level));
|
|
29
40
|
if (raw) {
|
|
30
41
|
try {
|
|
@@ -33,12 +44,13 @@ var RouteCache = class {
|
|
|
33
44
|
this.del(level);
|
|
34
45
|
return void 0;
|
|
35
46
|
}
|
|
47
|
+
this.memory.set(level, entry);
|
|
36
48
|
return entry;
|
|
37
49
|
} catch {
|
|
38
50
|
return void 0;
|
|
39
51
|
}
|
|
40
52
|
}
|
|
41
|
-
return
|
|
53
|
+
return void 0;
|
|
42
54
|
}
|
|
43
55
|
getFromMemory(level) {
|
|
44
56
|
const entry = this.memory.get(level);
|
|
@@ -62,14 +74,13 @@ var RouteCache = class {
|
|
|
62
74
|
ttl,
|
|
63
75
|
cachedAt: Date.now()
|
|
64
76
|
};
|
|
77
|
+
this.memory.set(resp.level, entry);
|
|
65
78
|
if (this.storage === "memory" || !this.backend) {
|
|
66
|
-
this.memory.set(resp.level, entry);
|
|
67
79
|
return;
|
|
68
80
|
}
|
|
69
81
|
try {
|
|
70
82
|
this.backend.setItem(this.key(resp.level), JSON.stringify(entry));
|
|
71
83
|
} catch {
|
|
72
|
-
this.memory.set(resp.level, entry);
|
|
73
84
|
}
|
|
74
85
|
}
|
|
75
86
|
del(level) {
|
|
@@ -249,14 +260,14 @@ function createInterceptorManager() {
|
|
|
249
260
|
return new InterceptorManagerImpl();
|
|
250
261
|
}
|
|
251
262
|
|
|
252
|
-
// src/adapters/
|
|
253
|
-
function
|
|
254
|
-
if (
|
|
255
|
-
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;
|
|
256
|
-
}
|
|
257
|
-
function isAbortError(err) {
|
|
263
|
+
// src/adapters/fetch-core.ts
|
|
264
|
+
function isAbortError(err, signal) {
|
|
265
|
+
if (signal?.aborted) return true;
|
|
258
266
|
const e = err;
|
|
259
|
-
|
|
267
|
+
if (!e) return false;
|
|
268
|
+
if (e.name === "AbortError") return true;
|
|
269
|
+
if (e.code === "ERR_CANCELED") return true;
|
|
270
|
+
return false;
|
|
260
271
|
}
|
|
261
272
|
function combineSignals(...signals) {
|
|
262
273
|
const valid = signals.filter((s) => !!s);
|
|
@@ -275,81 +286,92 @@ function combineSignals(...signals) {
|
|
|
275
286
|
}
|
|
276
287
|
return controller.signal;
|
|
277
288
|
}
|
|
278
|
-
function
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
}
|
|
289
|
+
function isPassthroughBody(body) {
|
|
290
|
+
if (body === null) return false;
|
|
291
|
+
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;
|
|
292
|
+
}
|
|
293
|
+
async function rawFetch(config) {
|
|
294
|
+
const signal = combineSignals(
|
|
295
|
+
config.signal,
|
|
296
|
+
config.timeout && config.timeout > 0 ? AbortSignal.timeout(config.timeout) : void 0
|
|
297
|
+
);
|
|
298
|
+
let url = config.url;
|
|
299
|
+
if (config.paramsSerializer && config.params) {
|
|
300
|
+
const qs = config.paramsSerializer(config.params);
|
|
301
|
+
if (qs) {
|
|
302
|
+
url = url.includes("?") ? `${url}&${qs}` : `${url}?${qs}`;
|
|
293
303
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
304
|
+
}
|
|
305
|
+
const headers = new Headers(config.headers);
|
|
306
|
+
const fetchInit = {
|
|
307
|
+
method: config.method,
|
|
308
|
+
headers
|
|
309
|
+
};
|
|
310
|
+
if (signal) fetchInit.signal = signal;
|
|
311
|
+
if (config.body !== void 0 && !["GET", "HEAD"].includes(config.method.toUpperCase())) {
|
|
312
|
+
if (typeof config.body === "string" || isPassthroughBody(config.body)) {
|
|
313
|
+
fetchInit.body = config.body;
|
|
314
|
+
} else {
|
|
315
|
+
fetchInit.body = JSON.stringify(config.body);
|
|
316
|
+
if (!headers.has("Content-Type")) {
|
|
317
|
+
headers.set("Content-Type", "application/json");
|
|
308
318
|
}
|
|
309
319
|
}
|
|
310
|
-
|
|
320
|
+
}
|
|
321
|
+
let res;
|
|
322
|
+
try {
|
|
323
|
+
res = await fetch(url, fetchInit);
|
|
324
|
+
} catch (e) {
|
|
325
|
+
if (isAbortError(e)) throw e;
|
|
326
|
+
throw new NetworkError(
|
|
327
|
+
e instanceof Error ? e.message : String(e),
|
|
328
|
+
config.route,
|
|
329
|
+
config.level,
|
|
330
|
+
e
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
const text = await res.text();
|
|
334
|
+
let data = text;
|
|
335
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
336
|
+
if (contentType.includes("application/json")) {
|
|
311
337
|
try {
|
|
312
|
-
|
|
313
|
-
} catch
|
|
314
|
-
if (isAbortError(e)) throw e;
|
|
315
|
-
throw new NetworkError(
|
|
316
|
-
e instanceof Error ? e.message : String(e),
|
|
317
|
-
finalConfig.route,
|
|
318
|
-
finalConfig.level,
|
|
319
|
-
e
|
|
320
|
-
);
|
|
321
|
-
}
|
|
322
|
-
const text = await res.text();
|
|
323
|
-
let data = text;
|
|
324
|
-
const contentType = res.headers.get("content-type") ?? "";
|
|
325
|
-
if (contentType.includes("application/json")) {
|
|
326
|
-
try {
|
|
327
|
-
data = JSON.parse(text);
|
|
328
|
-
} catch {
|
|
329
|
-
}
|
|
338
|
+
data = JSON.parse(text);
|
|
339
|
+
} catch {
|
|
330
340
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
341
|
+
}
|
|
342
|
+
const responseData = {
|
|
343
|
+
route: config.route,
|
|
344
|
+
level: config.level,
|
|
345
|
+
method: config.method,
|
|
346
|
+
url,
|
|
347
|
+
status: res.status,
|
|
348
|
+
headers: res.headers,
|
|
349
|
+
data,
|
|
350
|
+
config
|
|
351
|
+
};
|
|
352
|
+
if (res.status >= 200 && res.status < 300) {
|
|
353
|
+
return responseData;
|
|
354
|
+
}
|
|
355
|
+
throw new HTTPError(
|
|
356
|
+
`HTTP ${res.status} for route "${config.route}" (${config.method} ${url})`,
|
|
357
|
+
{
|
|
358
|
+
route: config.route,
|
|
359
|
+
level: config.level,
|
|
336
360
|
status: res.status,
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
)
|
|
352
|
-
);
|
|
361
|
+
url,
|
|
362
|
+
method: config.method
|
|
363
|
+
}
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// src/adapters/builtin-http.ts
|
|
368
|
+
function createBuiltinHttp(forgeInterceptors) {
|
|
369
|
+
const requestMgr = forgeInterceptors?.request ?? createInterceptorManager();
|
|
370
|
+
const responseMgr = forgeInterceptors?.response ?? createInterceptorManager();
|
|
371
|
+
const requestRaw = rawFetch;
|
|
372
|
+
async function request(config) {
|
|
373
|
+
const finalConfig = await runRequestInterceptors(requestMgr, config);
|
|
374
|
+
const source = Promise.resolve(finalConfig).then(requestRaw);
|
|
353
375
|
return runResponseInterceptors(
|
|
354
376
|
responseMgr,
|
|
355
377
|
source
|
|
@@ -362,6 +384,7 @@ function createBuiltinHttp(forgeInterceptors) {
|
|
|
362
384
|
const del = (url, config) => request({ ...config, url, method: "DELETE" });
|
|
363
385
|
return {
|
|
364
386
|
request,
|
|
387
|
+
requestRaw,
|
|
365
388
|
interceptors: {
|
|
366
389
|
request: requestMgr,
|
|
367
390
|
response: responseMgr
|
|
@@ -573,7 +596,6 @@ function createRouteForge(options) {
|
|
|
573
596
|
const loadingTracker = new LoadingTracker();
|
|
574
597
|
const explicitLevels = options.levels;
|
|
575
598
|
const explicitEager = options.eager;
|
|
576
|
-
const explicitStrict = options.strict ?? false;
|
|
577
599
|
const explicitEndpoint = options.endpoint;
|
|
578
600
|
let effectiveLevels = explicitLevels ?? [];
|
|
579
601
|
let effectiveEager = explicitEager ?? [];
|
|
@@ -581,17 +603,12 @@ function createRouteForge(options) {
|
|
|
581
603
|
let effectiveUrlPrefix = "";
|
|
582
604
|
let summaryUnassigned;
|
|
583
605
|
let backendHasUnassignedLevel = false;
|
|
584
|
-
const
|
|
606
|
+
const fetchSummary = async () => {
|
|
585
607
|
try {
|
|
586
|
-
const
|
|
587
|
-
const
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
`[route-forge] summary endpoint ${summaryUrl} unreachable (HTTP ${resp.status}); falling back to explicit options`
|
|
591
|
-
);
|
|
592
|
-
return null;
|
|
593
|
-
}
|
|
594
|
-
return await resp.json();
|
|
608
|
+
const base = baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL;
|
|
609
|
+
const ep = explicitEndpoint.startsWith("/") ? explicitEndpoint : `/${explicitEndpoint}`;
|
|
610
|
+
const data = await fetchMeta("__forge__.summary", `${base}${ep}`);
|
|
611
|
+
return data;
|
|
595
612
|
} catch (e) {
|
|
596
613
|
if (explicitLevels && explicitLevels.length > 0) {
|
|
597
614
|
console.warn(
|
|
@@ -601,8 +618,11 @@ function createRouteForge(options) {
|
|
|
601
618
|
}
|
|
602
619
|
throw new UnknownLevelError("(auto-discovery)");
|
|
603
620
|
}
|
|
604
|
-
}
|
|
605
|
-
|
|
621
|
+
};
|
|
622
|
+
let summaryPromise;
|
|
623
|
+
const summaryWaiters = [];
|
|
624
|
+
const whenSummary = () => summaryPromise ?? new Promise((resolve) => summaryWaiters.push(resolve));
|
|
625
|
+
const autoDiscoveryPromise = whenSummary().then((summary) => {
|
|
606
626
|
if (summary === null) {
|
|
607
627
|
return;
|
|
608
628
|
}
|
|
@@ -621,11 +641,6 @@ function createRouteForge(options) {
|
|
|
621
641
|
if (summary.config.url_prefix) {
|
|
622
642
|
effectiveUrlPrefix = summary.config.url_prefix.endsWith("/") ? summary.config.url_prefix.slice(0, -1) : summary.config.url_prefix;
|
|
623
643
|
}
|
|
624
|
-
if (summary.config.strict_mode && !explicitStrict) {
|
|
625
|
-
console.warn(
|
|
626
|
-
"[route-forge] backend strict_mode=true overrides frontend strict=false; forcing strict=true"
|
|
627
|
-
);
|
|
628
|
-
}
|
|
629
644
|
const backendLevels = Object.keys(summary.levels);
|
|
630
645
|
backendHasUnassignedLevel = backendLevels.includes(UNASSIGNED_LEVEL);
|
|
631
646
|
if (Array.isArray(summary.unassigned) && summary.unassigned.length > 0 && !backendHasUnassignedLevel) {
|
|
@@ -661,8 +676,12 @@ function createRouteForge(options) {
|
|
|
661
676
|
});
|
|
662
677
|
let autoDiscoveryCompleted = false;
|
|
663
678
|
let resolveReady;
|
|
664
|
-
|
|
679
|
+
let rejectReady;
|
|
680
|
+
const readyPromise = new Promise((resolve, reject) => {
|
|
665
681
|
resolveReady = resolve;
|
|
682
|
+
rejectReady = reject;
|
|
683
|
+
});
|
|
684
|
+
readyPromise.catch(() => {
|
|
666
685
|
});
|
|
667
686
|
const cacheTtl = cacheOpts.ttl ?? DEFAULT_CACHE_TTL;
|
|
668
687
|
const cacheStorage = cacheOpts.storage ?? "memory";
|
|
@@ -693,13 +712,20 @@ function createRouteForge(options) {
|
|
|
693
712
|
adapter,
|
|
694
713
|
forgeInterceptors: { request: requestInterceptors, response: responseInterceptors }
|
|
695
714
|
});
|
|
715
|
+
Promise.resolve().then(() => {
|
|
716
|
+
summaryPromise = fetchSummary();
|
|
717
|
+
for (const resolve of summaryWaiters) resolve(summaryPromise);
|
|
718
|
+
});
|
|
696
719
|
let adapterResolved = false;
|
|
697
720
|
let adapterObj = null;
|
|
698
721
|
async function ensureAdapter() {
|
|
699
722
|
if (!adapterResolved) {
|
|
700
723
|
adapterObj = await adapterPromise.catch((e) => {
|
|
701
724
|
if (e instanceof AdapterNotFoundError) throw e;
|
|
702
|
-
return resolveAdapter({
|
|
725
|
+
return resolveAdapter({
|
|
726
|
+
adapter: "builtin",
|
|
727
|
+
forgeInterceptors: { request: requestInterceptors, response: responseInterceptors }
|
|
728
|
+
});
|
|
703
729
|
});
|
|
704
730
|
adapterResolved = true;
|
|
705
731
|
}
|
|
@@ -725,33 +751,36 @@ function createRouteForge(options) {
|
|
|
725
751
|
const ep = effectiveEndpoint.startsWith("/") ? effectiveEndpoint : `/${effectiveEndpoint}`;
|
|
726
752
|
return `${base}${ep}/${encodeURIComponent(level)}`;
|
|
727
753
|
}
|
|
728
|
-
async function
|
|
754
|
+
async function fetchMeta(routeTag, url, level = "") {
|
|
729
755
|
const adp = await ensureAdapter();
|
|
730
756
|
const config = {
|
|
731
|
-
route:
|
|
757
|
+
route: routeTag,
|
|
732
758
|
level,
|
|
733
759
|
method: "GET",
|
|
734
|
-
url
|
|
760
|
+
url,
|
|
735
761
|
headers: { Accept: "application/json" },
|
|
736
762
|
params: {},
|
|
737
763
|
timeout,
|
|
738
764
|
meta: {
|
|
739
|
-
name:
|
|
740
|
-
uri:
|
|
765
|
+
name: routeTag,
|
|
766
|
+
uri: url,
|
|
741
767
|
methods: ["GET"],
|
|
742
768
|
parameters: [],
|
|
743
769
|
level
|
|
744
770
|
}
|
|
745
771
|
};
|
|
746
|
-
const
|
|
772
|
+
const doRawRequest = adp.requestRaw ?? adp.request;
|
|
773
|
+
const resp = await doRawRequest(config);
|
|
747
774
|
if (!resp || resp.status < 200 || resp.status >= 300) {
|
|
748
775
|
throw new HTTPError(
|
|
749
|
-
`Failed to
|
|
750
|
-
{ level, status: resp?.status, url
|
|
776
|
+
`Failed to fetch "${routeTag}": HTTP ${resp?.status}`,
|
|
777
|
+
{ level, status: resp?.status, url, method: "GET" }
|
|
751
778
|
);
|
|
752
779
|
}
|
|
753
|
-
|
|
754
|
-
|
|
780
|
+
return resp.data;
|
|
781
|
+
}
|
|
782
|
+
async function fetchLevel(level) {
|
|
783
|
+
return await fetchMeta(`__forge__.load.${level}`, buildUrl(level), level);
|
|
755
784
|
}
|
|
756
785
|
async function loadOne(level) {
|
|
757
786
|
if (autoDiscoveryError) throw autoDiscoveryError;
|
|
@@ -923,7 +952,7 @@ function createRouteForge(options) {
|
|
|
923
952
|
},
|
|
924
953
|
(err) => {
|
|
925
954
|
if (err instanceof ForgeError) throw err;
|
|
926
|
-
if (
|
|
955
|
+
if (isAbortError(err, signal)) {
|
|
927
956
|
throw new RequestAbortedError(meta.name, meta.level, err);
|
|
928
957
|
}
|
|
929
958
|
throw new NetworkError(
|
|
@@ -992,15 +1021,22 @@ function createRouteForge(options) {
|
|
|
992
1021
|
}
|
|
993
1022
|
void autoDiscoveryPromise.then(() => {
|
|
994
1023
|
autoDiscoveryCompleted = true;
|
|
995
|
-
options.onSummaryReady?.();
|
|
996
1024
|
if (effectiveEager.length > 0) {
|
|
997
|
-
return Promise.
|
|
998
|
-
|
|
1025
|
+
return Promise.allSettled(effectiveEager.map((lvl) => load(lvl))).then((results) => {
|
|
1026
|
+
results.forEach((r, i) => {
|
|
1027
|
+
if (r.status === "rejected") {
|
|
1028
|
+
console.error(
|
|
1029
|
+
`[route-forge] eager load failed for level "${effectiveEager[i]}":`,
|
|
1030
|
+
r.reason
|
|
1031
|
+
);
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
999
1034
|
});
|
|
1000
1035
|
}
|
|
1001
1036
|
}).then(() => {
|
|
1002
1037
|
resolveReady(forgeInstance);
|
|
1003
|
-
}).catch(() => {
|
|
1038
|
+
}).catch((e) => {
|
|
1039
|
+
rejectReady(e);
|
|
1004
1040
|
});
|
|
1005
1041
|
function ready(onFulfilled, onRejected) {
|
|
1006
1042
|
if (onFulfilled) {
|
|
@@ -1011,7 +1047,8 @@ function createRouteForge(options) {
|
|
|
1011
1047
|
}
|
|
1012
1048
|
const forgeResolver = { load, hasRoute };
|
|
1013
1049
|
function createBoundForge(level, prefix) {
|
|
1014
|
-
const levelLoadedPromise = load(level)
|
|
1050
|
+
const levelLoadedPromise = load(level);
|
|
1051
|
+
levelLoadedPromise.catch(() => {
|
|
1015
1052
|
});
|
|
1016
1053
|
const apiFn = prefix ? (name, params) => resolveRouteName(forgeResolver, level, prefix, name).then(
|
|
1017
1054
|
(resolved) => api(level, resolved, params)
|
|
@@ -1145,14 +1182,6 @@ function resolveApiParams(input) {
|
|
|
1145
1182
|
}
|
|
1146
1183
|
return { pathParams, query, body, headers, timeout: perCallTimeout };
|
|
1147
1184
|
}
|
|
1148
|
-
function isAbortError2(err, signal) {
|
|
1149
|
-
if (signal?.aborted) return true;
|
|
1150
|
-
const e = err;
|
|
1151
|
-
if (!e) return false;
|
|
1152
|
-
if (e.name === "AbortError") return true;
|
|
1153
|
-
if (e.code === "ERR_CANCELED") return true;
|
|
1154
|
-
return false;
|
|
1155
|
-
}
|
|
1156
1185
|
|
|
1157
1186
|
export { AdapterNotFoundError, ForgeError, HTTPError, InterceptorManagerImpl, InvalidInterceptorReturnError, LoadingTracker, MissingRouteParamError, NetworkError, RequestAbortedError, RouteCache, UnknownLevelError, UnknownRouteError, createInterceptorManager, createRouteForge, resolveRouteName, resolveRouteNameSync };
|
|
1158
1187
|
//# sourceMappingURL=index.js.map
|