@route-forge/core 0.3.0 → 1.0.2
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 +104 -4
- package/dist/codegen.cjs +5 -1
- package/dist/codegen.cjs.map +1 -1
- package/dist/codegen.d.cts +1 -1
- package/dist/codegen.d.ts +1 -1
- package/dist/codegen.js +5 -1
- package/dist/codegen.js.map +1 -1
- package/dist/index.cjs +245 -96
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -10
- package/dist/index.d.ts +4 -10
- package/dist/index.js +245 -96
- package/dist/index.js.map +1 -1
- package/dist/{types-CBurRtGK.d.cts → types-DExMMUu1.d.cts} +105 -15
- package/dist/{types-CBurRtGK.d.ts → types-DExMMUu1.d.ts} +105 -15
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -28,17 +28,19 @@ var RouteCache = class {
|
|
|
28
28
|
return this.getFromMemory(level);
|
|
29
29
|
}
|
|
30
30
|
const raw = this.backend.getItem(this.key(level));
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
if (raw) {
|
|
32
|
+
try {
|
|
33
|
+
const entry = JSON.parse(raw);
|
|
34
|
+
if (this.isExpired(entry)) {
|
|
35
|
+
this.del(level);
|
|
36
|
+
return void 0;
|
|
37
|
+
}
|
|
38
|
+
return entry;
|
|
39
|
+
} catch {
|
|
36
40
|
return void 0;
|
|
37
41
|
}
|
|
38
|
-
return entry;
|
|
39
|
-
} catch {
|
|
40
|
-
return void 0;
|
|
41
42
|
}
|
|
43
|
+
return this.getFromMemory(level);
|
|
42
44
|
}
|
|
43
45
|
getFromMemory(level) {
|
|
44
46
|
const entry = this.memory.get(level);
|
|
@@ -50,7 +52,12 @@ var RouteCache = class {
|
|
|
50
52
|
return entry;
|
|
51
53
|
}
|
|
52
54
|
set(resp) {
|
|
53
|
-
|
|
55
|
+
let ttl;
|
|
56
|
+
if (resp.cache !== void 0 && resp.cache !== null) {
|
|
57
|
+
ttl = resp.cache > 0 ? Math.min(resp.cache, this.fallbackTtl) : resp.cache;
|
|
58
|
+
} else {
|
|
59
|
+
ttl = this.fallbackTtl;
|
|
60
|
+
}
|
|
54
61
|
const entry = {
|
|
55
62
|
level: resp.level,
|
|
56
63
|
routes: resp.routes,
|
|
@@ -135,14 +142,6 @@ var MissingRouteParamError = class extends ForgeError {
|
|
|
135
142
|
});
|
|
136
143
|
}
|
|
137
144
|
};
|
|
138
|
-
var InsufficientAuthError = class extends ForgeError {
|
|
139
|
-
constructor(level) {
|
|
140
|
-
super(`Insufficient auth: level "${level}" requires login`, {
|
|
141
|
-
code: "RF_FE_004",
|
|
142
|
-
level
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
145
|
var AdapterNotFoundError = class extends ForgeError {
|
|
147
146
|
constructor(adapter) {
|
|
148
147
|
super(`Adapter "${adapter}" not available; install axios or use 'builtin'`, {
|
|
@@ -243,6 +242,10 @@ function createInterceptorManager() {
|
|
|
243
242
|
}
|
|
244
243
|
|
|
245
244
|
// src/adapters/builtin-http.ts
|
|
245
|
+
function isPassthroughBody(body) {
|
|
246
|
+
if (body === null) return false;
|
|
247
|
+
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;
|
|
248
|
+
}
|
|
246
249
|
function createBuiltinHttp(forgeInterceptors) {
|
|
247
250
|
const requestMgr = forgeInterceptors?.request ?? createInterceptorManager();
|
|
248
251
|
const responseMgr = forgeInterceptors?.response ?? createInterceptorManager();
|
|
@@ -256,15 +259,33 @@ function createBuiltinHttp(forgeInterceptors) {
|
|
|
256
259
|
url = url.includes("?") ? `${url}&${qs}` : `${url}?${qs}`;
|
|
257
260
|
}
|
|
258
261
|
}
|
|
262
|
+
const headers = new Headers(finalConfig.headers);
|
|
259
263
|
const fetchInit = {
|
|
260
264
|
method: finalConfig.method,
|
|
261
|
-
headers
|
|
265
|
+
headers
|
|
262
266
|
};
|
|
263
267
|
if (signal) fetchInit.signal = signal;
|
|
264
268
|
if (finalConfig.body !== void 0 && !["GET", "HEAD"].includes(finalConfig.method.toUpperCase())) {
|
|
265
|
-
|
|
269
|
+
if (typeof finalConfig.body === "string" || isPassthroughBody(finalConfig.body)) {
|
|
270
|
+
fetchInit.body = finalConfig.body;
|
|
271
|
+
} else {
|
|
272
|
+
fetchInit.body = JSON.stringify(finalConfig.body);
|
|
273
|
+
if (!headers.has("Content-Type")) {
|
|
274
|
+
headers.set("Content-Type", "application/json");
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
let res;
|
|
279
|
+
try {
|
|
280
|
+
res = await fetch(url, fetchInit);
|
|
281
|
+
} catch (e) {
|
|
282
|
+
throw new NetworkError(
|
|
283
|
+
e instanceof Error ? e.message : String(e),
|
|
284
|
+
finalConfig.route,
|
|
285
|
+
finalConfig.level,
|
|
286
|
+
e
|
|
287
|
+
);
|
|
266
288
|
}
|
|
267
|
-
const res = await fetch(url, fetchInit);
|
|
268
289
|
const text = await res.text();
|
|
269
290
|
let data = text;
|
|
270
291
|
const contentType = res.headers.get("content-type") ?? "";
|
|
@@ -284,9 +305,21 @@ function createBuiltinHttp(forgeInterceptors) {
|
|
|
284
305
|
data,
|
|
285
306
|
config: finalConfig
|
|
286
307
|
};
|
|
308
|
+
const source = res.status >= 200 && res.status < 300 ? Promise.resolve(responseData) : Promise.reject(
|
|
309
|
+
new HTTPError(
|
|
310
|
+
`HTTP ${res.status} for route "${finalConfig.route}" (${finalConfig.method} ${url})`,
|
|
311
|
+
{
|
|
312
|
+
route: finalConfig.route,
|
|
313
|
+
level: finalConfig.level,
|
|
314
|
+
status: res.status,
|
|
315
|
+
url,
|
|
316
|
+
method: finalConfig.method
|
|
317
|
+
}
|
|
318
|
+
)
|
|
319
|
+
);
|
|
287
320
|
return runResponseInterceptors(
|
|
288
321
|
responseMgr,
|
|
289
|
-
|
|
322
|
+
source
|
|
290
323
|
);
|
|
291
324
|
}
|
|
292
325
|
const get = (url, config) => request({ ...config, url, method: "GET" });
|
|
@@ -310,6 +343,15 @@ function createBuiltinHttp(forgeInterceptors) {
|
|
|
310
343
|
}
|
|
311
344
|
|
|
312
345
|
// src/adapters/axios.ts
|
|
346
|
+
function toHeaders(raw) {
|
|
347
|
+
if (!raw) return new Headers();
|
|
348
|
+
const init = typeof raw.toJSON === "function" ? raw.toJSON() : raw;
|
|
349
|
+
try {
|
|
350
|
+
return new Headers(init);
|
|
351
|
+
} catch {
|
|
352
|
+
return new Headers();
|
|
353
|
+
}
|
|
354
|
+
}
|
|
313
355
|
async function wrapAxiosAdapter() {
|
|
314
356
|
let axios;
|
|
315
357
|
try {
|
|
@@ -326,23 +368,41 @@ async function wrapAxiosAdapter() {
|
|
|
326
368
|
if (!axios || typeof axios.request !== "function") return null;
|
|
327
369
|
async function request(config) {
|
|
328
370
|
const headers = { ...config.headers };
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
371
|
+
try {
|
|
372
|
+
const res = await axios.request({
|
|
373
|
+
url: config.url,
|
|
374
|
+
method: config.method,
|
|
375
|
+
headers,
|
|
376
|
+
data: config.body,
|
|
377
|
+
// axios 会处理 baseURL/transformRequest 等 defaults;timeout 透传保证超时语义与 builtin 一致
|
|
378
|
+
timeout: config.timeout
|
|
379
|
+
});
|
|
380
|
+
return {
|
|
381
|
+
route: config.route,
|
|
382
|
+
level: config.level,
|
|
383
|
+
method: config.method,
|
|
384
|
+
url: config.url,
|
|
385
|
+
status: res.status,
|
|
386
|
+
headers: toHeaders(res.headers),
|
|
387
|
+
data: res.data,
|
|
388
|
+
config
|
|
389
|
+
};
|
|
390
|
+
} catch (e) {
|
|
391
|
+
if (e && e.response) {
|
|
392
|
+
const resp = e.response;
|
|
393
|
+
return {
|
|
394
|
+
route: config.route,
|
|
395
|
+
level: config.level,
|
|
396
|
+
method: config.method,
|
|
397
|
+
url: config.url,
|
|
398
|
+
status: resp.status,
|
|
399
|
+
headers: toHeaders(resp.headers),
|
|
400
|
+
data: resp.data,
|
|
401
|
+
config
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
throw e;
|
|
405
|
+
}
|
|
346
406
|
}
|
|
347
407
|
return { request, interceptors: void 0 };
|
|
348
408
|
}
|
|
@@ -369,6 +429,65 @@ async function resolveAdapter(opts) {
|
|
|
369
429
|
return createBuiltinHttp(opts.forgeInterceptors);
|
|
370
430
|
}
|
|
371
431
|
|
|
432
|
+
// src/loading.ts
|
|
433
|
+
var LoadingTracker = class {
|
|
434
|
+
constructor() {
|
|
435
|
+
/** 当前并发请求计数 */
|
|
436
|
+
this.count = 0;
|
|
437
|
+
/** 订阅者集合 */
|
|
438
|
+
this.subscribers = /* @__PURE__ */ new Set();
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* 开始一次加载(计数器 +1)
|
|
442
|
+
*/
|
|
443
|
+
start() {
|
|
444
|
+
this.count++;
|
|
445
|
+
this.notify();
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* 结束一次加载(计数器 -1)
|
|
449
|
+
*/
|
|
450
|
+
stop() {
|
|
451
|
+
this.count = Math.max(0, this.count - 1);
|
|
452
|
+
this.notify();
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* 查询当前是否处于加载中
|
|
456
|
+
*/
|
|
457
|
+
isLoading() {
|
|
458
|
+
return this.count > 0;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* 获取当前并发计数
|
|
462
|
+
*/
|
|
463
|
+
getCount() {
|
|
464
|
+
return this.count;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* 订阅加载状态变更
|
|
468
|
+
* @returns 取消订阅函数
|
|
469
|
+
*/
|
|
470
|
+
subscribe(cb) {
|
|
471
|
+
this.subscribers.add(cb);
|
|
472
|
+
return () => {
|
|
473
|
+
this.subscribers.delete(cb);
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
/** 通知所有订阅者 */
|
|
477
|
+
notify() {
|
|
478
|
+
const event = {
|
|
479
|
+
loading: this.count > 0,
|
|
480
|
+
count: this.count
|
|
481
|
+
};
|
|
482
|
+
for (const cb of this.subscribers) {
|
|
483
|
+
try {
|
|
484
|
+
cb(event);
|
|
485
|
+
} catch {
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
|
|
372
491
|
// src/forge.ts
|
|
373
492
|
var DEFAULT_TIMEOUT = 3e4;
|
|
374
493
|
var DEFAULT_CACHE_TTL = 3600;
|
|
@@ -378,10 +497,10 @@ function createRouteForge(options) {
|
|
|
378
497
|
adapter = "auto",
|
|
379
498
|
timeout = DEFAULT_TIMEOUT,
|
|
380
499
|
baseURL = "",
|
|
381
|
-
auth,
|
|
382
500
|
interceptors: declarativeInterceptors,
|
|
383
501
|
cache: cacheOpts = {}
|
|
384
502
|
} = options;
|
|
503
|
+
const loadingTracker = new LoadingTracker();
|
|
385
504
|
const explicitLevels = options.levels;
|
|
386
505
|
const explicitEager = options.eager;
|
|
387
506
|
const explicitStrict = options.strict ?? false;
|
|
@@ -415,6 +534,12 @@ function createRouteForge(options) {
|
|
|
415
534
|
if (summary === null) {
|
|
416
535
|
return;
|
|
417
536
|
}
|
|
537
|
+
const schemaVersion = summary.schemaVersion ?? 1;
|
|
538
|
+
if (schemaVersion > 1) {
|
|
539
|
+
console.warn(
|
|
540
|
+
`[route-forge] backend schemaVersion=${schemaVersion} > client supported 1; some features may be unavailable`
|
|
541
|
+
);
|
|
542
|
+
}
|
|
418
543
|
if (summary.config.endpoint_prefix && summary.config.endpoint_prefix !== explicitEndpoint) {
|
|
419
544
|
console.warn(
|
|
420
545
|
`[route-forge] backend endpoint_prefix "${summary.config.endpoint_prefix}" overrides frontend endpoint "${explicitEndpoint}"`
|
|
@@ -442,8 +567,12 @@ function createRouteForge(options) {
|
|
|
442
567
|
} else {
|
|
443
568
|
effectiveLevels = backendLevels;
|
|
444
569
|
}
|
|
570
|
+
const backendEager = backendLevels.filter((lvl) => summary.levels[lvl]?.load === "eager");
|
|
445
571
|
if (!explicitEager) {
|
|
446
|
-
effectiveEager =
|
|
572
|
+
effectiveEager = backendEager;
|
|
573
|
+
} else {
|
|
574
|
+
const union = /* @__PURE__ */ new Set([...backendEager, ...explicitEager]);
|
|
575
|
+
effectiveEager = [...union];
|
|
447
576
|
}
|
|
448
577
|
});
|
|
449
578
|
autoDiscoveryPromise.catch(() => {
|
|
@@ -454,15 +583,23 @@ function createRouteForge(options) {
|
|
|
454
583
|
const requestInterceptors = new InterceptorManagerImpl();
|
|
455
584
|
const responseInterceptors = new InterceptorManagerImpl();
|
|
456
585
|
if (declarativeInterceptors?.request) {
|
|
457
|
-
for (const
|
|
458
|
-
|
|
459
|
-
|
|
586
|
+
for (const entry of declarativeInterceptors.request) {
|
|
587
|
+
if (typeof entry === "function") {
|
|
588
|
+
requestInterceptors.use(entry);
|
|
589
|
+
} else {
|
|
590
|
+
const [onFulfilled, onRejected] = entry;
|
|
591
|
+
requestInterceptors.use(onFulfilled, onRejected);
|
|
592
|
+
}
|
|
460
593
|
}
|
|
461
594
|
}
|
|
462
595
|
if (declarativeInterceptors?.response) {
|
|
463
|
-
for (const
|
|
464
|
-
|
|
465
|
-
|
|
596
|
+
for (const entry of declarativeInterceptors.response) {
|
|
597
|
+
if (typeof entry === "function") {
|
|
598
|
+
responseInterceptors.use(entry);
|
|
599
|
+
} else {
|
|
600
|
+
const [onFulfilled, onRejected] = entry;
|
|
601
|
+
responseInterceptors.use(onFulfilled, onRejected);
|
|
602
|
+
}
|
|
466
603
|
}
|
|
467
604
|
}
|
|
468
605
|
const adapterPromise = resolveAdapter({
|
|
@@ -482,14 +619,6 @@ function createRouteForge(options) {
|
|
|
482
619
|
return adapterObj;
|
|
483
620
|
}
|
|
484
621
|
const inflight = /* @__PURE__ */ new Map();
|
|
485
|
-
function isAuthRequired(level) {
|
|
486
|
-
return Boolean(auth?.levels?.[level]);
|
|
487
|
-
}
|
|
488
|
-
function assertAuth(level) {
|
|
489
|
-
if (isAuthRequired(level) && auth?.state && !auth.state()) {
|
|
490
|
-
throw new InsufficientAuthError(level);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
622
|
function assertLevelDeclared(level) {
|
|
494
623
|
if (!effectiveLevels.includes(level)) {
|
|
495
624
|
throw new UnknownLevelError(level);
|
|
@@ -520,14 +649,16 @@ function createRouteForge(options) {
|
|
|
520
649
|
};
|
|
521
650
|
const resp = await adp.request(config);
|
|
522
651
|
if (!resp || resp.status < 200 || resp.status >= 300) {
|
|
523
|
-
throw new
|
|
652
|
+
throw new HTTPError(
|
|
653
|
+
`Failed to load level "${level}": HTTP ${resp?.status}`,
|
|
654
|
+
{ level, status: resp?.status, url: buildUrl(level), method: "GET" }
|
|
655
|
+
);
|
|
524
656
|
}
|
|
525
657
|
const data = resp.data;
|
|
526
658
|
return data;
|
|
527
659
|
}
|
|
528
660
|
async function loadOne(level) {
|
|
529
661
|
assertLevelDeclared(level);
|
|
530
|
-
assertAuth(level);
|
|
531
662
|
if (cache.get(level)) return;
|
|
532
663
|
const existing = inflight.get(level);
|
|
533
664
|
if (existing) return existing;
|
|
@@ -555,27 +686,33 @@ function createRouteForge(options) {
|
|
|
555
686
|
return buildRequestUrl(meta, params ?? {});
|
|
556
687
|
}
|
|
557
688
|
function buildRequestUrl(meta, params) {
|
|
558
|
-
let uri = meta.uri;
|
|
559
689
|
const defaults = meta.parameter_defaults ?? {};
|
|
560
690
|
const missingRequired = [];
|
|
691
|
+
const values = {};
|
|
561
692
|
for (const p of meta.parameters) {
|
|
562
693
|
let v = params[p];
|
|
563
694
|
if ((v === void 0 || v === null) && p in defaults) {
|
|
564
695
|
v = defaults[p];
|
|
565
696
|
}
|
|
566
697
|
if (v === void 0 || v === null) {
|
|
567
|
-
if (uri.includes(`{${p}?}`)) {
|
|
568
|
-
|
|
569
|
-
continue;
|
|
698
|
+
if (!meta.uri.includes(`{${p}?}`)) {
|
|
699
|
+
missingRequired.push(p);
|
|
570
700
|
}
|
|
571
|
-
missingRequired.push(p);
|
|
572
701
|
} else {
|
|
573
|
-
|
|
702
|
+
values[p] = v;
|
|
574
703
|
}
|
|
575
704
|
}
|
|
576
705
|
if (missingRequired.length > 0) {
|
|
577
706
|
throw new MissingRouteParamError(meta.name, missingRequired);
|
|
578
707
|
}
|
|
708
|
+
let uri = meta.uri.replace(/\{([^{}]+)\}/g, (match, raw) => {
|
|
709
|
+
const optional = raw.endsWith("?");
|
|
710
|
+
const name = optional ? raw.slice(0, -1) : raw;
|
|
711
|
+
if (values[name] !== void 0) {
|
|
712
|
+
return encodeURIComponent(String(values[name]));
|
|
713
|
+
}
|
|
714
|
+
return optional ? "" : match;
|
|
715
|
+
});
|
|
579
716
|
uri = uri.replace(/\/+/g, "/").replace(/\/$/, "");
|
|
580
717
|
if (effectiveUrlPrefix.includes("://")) {
|
|
581
718
|
const prefix2 = effectiveUrlPrefix.endsWith("/") ? effectiveUrlPrefix.slice(0, -1) : effectiveUrlPrefix;
|
|
@@ -603,8 +740,7 @@ function createRouteForge(options) {
|
|
|
603
740
|
return doApiCall(meta, params);
|
|
604
741
|
}
|
|
605
742
|
async function doApiCall(meta, params) {
|
|
606
|
-
|
|
607
|
-
const { pathParams, query, body, headers } = resolveApiParams(params);
|
|
743
|
+
const { pathParams, query, body, headers, timeout: perCallTimeout } = resolveApiParams(params);
|
|
608
744
|
const method = pickMethod(meta);
|
|
609
745
|
const urlWithQuery = appendQuery(buildRequestUrl(meta, pathParams), query);
|
|
610
746
|
const config = {
|
|
@@ -615,47 +751,57 @@ function createRouteForge(options) {
|
|
|
615
751
|
headers: { Accept: "application/json", ...headers ?? {} },
|
|
616
752
|
body,
|
|
617
753
|
params: pathParams,
|
|
618
|
-
timeout,
|
|
754
|
+
timeout: perCallTimeout ?? timeout,
|
|
619
755
|
meta
|
|
620
756
|
};
|
|
621
757
|
const adp = await ensureAdapter();
|
|
622
758
|
const finalConfig = adp.runsInterceptors ? config : await runRequestInterceptors(requestInterceptors, config);
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
route
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
759
|
+
loadingTracker.start();
|
|
760
|
+
try {
|
|
761
|
+
const source = adp.request(finalConfig).then(
|
|
762
|
+
(resp) => {
|
|
763
|
+
if (resp.status < 200 || resp.status >= 300) {
|
|
764
|
+
throw new HTTPError(
|
|
765
|
+
`HTTP ${resp.status} for route "${resp.route}" (${resp.method} ${resp.url})`,
|
|
766
|
+
{
|
|
767
|
+
route: resp.route,
|
|
768
|
+
level: resp.level,
|
|
769
|
+
status: resp.status,
|
|
770
|
+
url: resp.url,
|
|
771
|
+
method: resp.method
|
|
772
|
+
}
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
return resp;
|
|
776
|
+
},
|
|
777
|
+
(err) => {
|
|
778
|
+
if (err instanceof ForgeError) throw err;
|
|
779
|
+
throw new NetworkError(
|
|
780
|
+
err instanceof Error ? err.message : String(err),
|
|
781
|
+
meta.name,
|
|
782
|
+
meta.level,
|
|
783
|
+
err
|
|
635
784
|
);
|
|
636
785
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
meta.name,
|
|
644
|
-
meta.level,
|
|
645
|
-
err
|
|
646
|
-
);
|
|
647
|
-
}
|
|
648
|
-
);
|
|
649
|
-
if (adp.runsInterceptors) return source;
|
|
650
|
-
return runResponseInterceptors(responseInterceptors, source);
|
|
786
|
+
);
|
|
787
|
+
const result = adp.runsInterceptors ? await source : await runResponseInterceptors(responseInterceptors, source);
|
|
788
|
+
return result;
|
|
789
|
+
} finally {
|
|
790
|
+
loadingTracker.stop();
|
|
791
|
+
}
|
|
651
792
|
}
|
|
652
793
|
function invalidate(level) {
|
|
653
|
-
if (level)
|
|
654
|
-
|
|
794
|
+
if (level === void 0) {
|
|
795
|
+
cache.clear();
|
|
796
|
+
} else if (Array.isArray(level)) {
|
|
797
|
+
for (const lvl of level) cache.del(lvl);
|
|
798
|
+
} else {
|
|
799
|
+
cache.del(level);
|
|
800
|
+
}
|
|
655
801
|
}
|
|
656
802
|
function isLoaded(level) {
|
|
657
803
|
if (level) return cache.get(level) !== void 0;
|
|
658
|
-
return effectiveLevels.every((lvl) => cache.get(lvl) !== void 0);
|
|
804
|
+
return effectiveLevels.length > 0 && effectiveLevels.every((lvl) => cache.get(lvl) !== void 0);
|
|
659
805
|
}
|
|
660
806
|
function hasRoute(level, name) {
|
|
661
807
|
return findRouteMeta(level, name) !== void 0;
|
|
@@ -700,6 +846,8 @@ function createRouteForge(options) {
|
|
|
700
846
|
isLoaded,
|
|
701
847
|
hasRoute,
|
|
702
848
|
getRoutes,
|
|
849
|
+
isLoading: () => loadingTracker.isLoading(),
|
|
850
|
+
onLoadingChange: (cb) => loadingTracker.subscribe(cb),
|
|
703
851
|
interceptors: {
|
|
704
852
|
request: requestInterceptors,
|
|
705
853
|
response: responseInterceptors
|
|
@@ -727,6 +875,7 @@ function resolveApiParams(input) {
|
|
|
727
875
|
query: rawQuery,
|
|
728
876
|
body: rawBody,
|
|
729
877
|
headers: rawHeaders,
|
|
878
|
+
timeout: perCallTimeout,
|
|
730
879
|
...flatRest
|
|
731
880
|
} = input;
|
|
732
881
|
const pathParams = explicitParams ? { ...explicitParams } : {};
|
|
@@ -759,15 +908,15 @@ function resolveApiParams(input) {
|
|
|
759
908
|
pathParams.headers = rawHeaders;
|
|
760
909
|
}
|
|
761
910
|
}
|
|
762
|
-
return { pathParams, query, body, headers };
|
|
911
|
+
return { pathParams, query, body, headers, timeout: perCallTimeout };
|
|
763
912
|
}
|
|
764
913
|
|
|
765
914
|
exports.AdapterNotFoundError = AdapterNotFoundError;
|
|
766
915
|
exports.ForgeError = ForgeError;
|
|
767
916
|
exports.HTTPError = HTTPError;
|
|
768
|
-
exports.InsufficientAuthError = InsufficientAuthError;
|
|
769
917
|
exports.InterceptorManagerImpl = InterceptorManagerImpl;
|
|
770
918
|
exports.InvalidInterceptorReturnError = InvalidInterceptorReturnError;
|
|
919
|
+
exports.LoadingTracker = LoadingTracker;
|
|
771
920
|
exports.MissingRouteParamError = MissingRouteParamError;
|
|
772
921
|
exports.NetworkError = NetworkError;
|
|
773
922
|
exports.RouteCache = RouteCache;
|