@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 CHANGED
@@ -196,18 +196,22 @@ unsub()
196
196
  | Level load | 拉取某层级路由元数据 | `forge.isLoaded(level)` |
197
197
  | API request | 业务接口请求 | `forge.isLoading()` |
198
198
 
199
- ### `onSummaryReady` 回调
199
+ ### `ready()` 后挂载应用
200
200
 
201
- 推荐在回调中挂载应用,确保路由数据就绪:
201
+ 推荐在 `ready()` resolve 后挂载应用(auto-discovery + eager 层级全部完成),
202
+ 失败走 `catch`(onSummaryReady 回调已移除,统一走 ready——完整成功/失败语义链):
202
203
 
203
204
  ```ts
204
205
  const forge = createRouteForge({
205
206
  endpoint: '/_forge/routes',
206
- onSummaryReady: () => {
207
- // 摘要端点完成,路由数据已可用
208
- app.mount('#app')
209
- },
210
207
  })
208
+ // 成功:摘要 + eager 完成后挂载;失败:接住 reject,避免静默白屏
209
+ forge.ready()
210
+ .then(() => app.mount('#app'))
211
+ .catch((err) => {
212
+ console.error('[route-forge] init failed', err)
213
+ // 按业务需要降级:渲染错误页 / 重试 / 上报
214
+ })
211
215
  ```
212
216
 
213
217
  ### `forge.ready()` 方法
@@ -281,6 +285,46 @@ const prefixed = bound.useRoutePrefix('posts') // 追加前缀
281
285
  `ForgeError (RF_FE_010)`, 防止在路由数据未就绪时返回错误结果。`api()` 不受影响(内部自动 await
282
286
  discovery)。
283
287
 
288
+ ## 工具导出
289
+
290
+ 除 `createRouteForge` 外,core 包还导出以下工具件,供高级场景按需使用:
291
+
292
+ | 导出 | 说明 |
293
+ |-----------------------------|----------------------------------------------------------------------------------------|
294
+ | `createInterceptorManager` | 创建拦截器管理器(`use`/`eject`/`clear`),供自定义 Fetcher 复用统一拦截器实现 |
295
+ | `RouteCache` | 按层级隔离的路由缓存类(memory / sessionStorage / localStorage,TTL 过期),可独立使用 |
296
+ | `LoadingTracker` | 加载状态跟踪器(引用计数 + 订阅),框架适配层可基于它实现全局加载指示 |
297
+ | `resolveRouteName` | 前缀歧义异步消解(`prefix.suffix` 优先,回退后缀本身),`api()` 调用路径使用 |
298
+ | `resolveRouteNameSync` | 前缀歧义同步消解(基于已加载缓存),`route()` / `url()` 调用路径使用 |
299
+
300
+ ## 错误参考
301
+
302
+ 所有错误均为 `ForgeError` 子类,携带稳定的 `code` 字段,可按 `code` 分支处理:
303
+
304
+ | 错误类 | code | 触发场景 |
305
+ |-------------------------------|-------------|------------------------------------------------------|
306
+ | `UnknownRouteError` | `RF_FE_001` | 路由名不存在于已加载层级中 |
307
+ | `UnknownLevelError` | `RF_FE_002` | 层级未在 levels 声明(前端校验始终开启) |
308
+ | `MissingRouteParamError` | `RF_FE_003` | 必填路径参数缺失(无后端默认值) |
309
+ | `AdapterNotFoundError` | `RF_FE_005` | `adapter: 'axios'` 但宿主未安装/无有效 axios |
310
+ | `InvalidInterceptorReturnError` | `RF_FE_006` | 请求拦截器未返回 RequestConfig 对象 |
311
+ | `NetworkError` | `RF_FE_007` | 网络层失败(DNS、连接被拒等),`cause` 保留原始错误 |
312
+ | `HTTPError` | `RF_FE_008` | HTTP 非 2xx,`context.status` 为状态码 |
313
+ | `RequestAbortedError` | `RF_FE_009` | 请求被 `abort()` / AbortSignal 取消 |
314
+ | `ForgeError`(守卫) | `RF_FE_010` | auto-discovery 未完成时调用 `route()`/`hasRoute()` |
315
+
316
+ 错误对象结构:
317
+
318
+ ```ts
319
+ {
320
+ code: 'RF_FE_008', // 稳定错误码
321
+ route?: string, // 关联路由名
322
+ level?: string, // 关联层级
323
+ context?: Record<string, unknown>, // 附加上下文(如 HTTP 状态码)
324
+ cause?: unknown, // 原始底层错误
325
+ }
326
+ ```
327
+
284
328
  ## 文档
285
329
 
286
330
  - 仓库主页: https://github.com/route-forge/route-forge
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { R as RouteMeta } from './types-Cd1c1OdJ.cjs';
2
+ import { R as RouteMeta } from './types-BvLdl02f.cjs';
3
3
 
4
4
  /**
5
5
  * @route-forge/core codegen CLI
package/dist/codegen.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { R as RouteMeta } from './types-Cd1c1OdJ.js';
2
+ import { R as RouteMeta } from './types-BvLdl02f.js';
3
3
 
4
4
  /**
5
5
  * @route-forge/core codegen CLI
package/dist/index.cjs CHANGED
@@ -16,9 +16,18 @@ function pickStorage(storage) {
16
16
  var RouteCache = class {
17
17
  constructor(opts) {
18
18
  this.memory = /* @__PURE__ */ new Map();
19
+ /** 其他 tab 修改 storage 时失效对应镜像(storage 事件:自己的写不触发,自己的写经 set/del 已同步) */
20
+ this.onStorageEvent = (e) => {
21
+ if (!e.key) return;
22
+ if (!e.key.startsWith(KEY_PREFIX)) return;
23
+ this.memory.delete(e.key.slice(KEY_PREFIX.length));
24
+ };
19
25
  this.storage = opts.storage;
20
26
  this.fallbackTtl = opts.ttl;
21
27
  this.backend = pickStorage(opts.storage);
28
+ if (this.backend && typeof globalThis.addEventListener === "function") {
29
+ globalThis.addEventListener("storage", this.onStorageEvent);
30
+ }
22
31
  }
23
32
  key(level) {
24
33
  return `${KEY_PREFIX}${level}`;
@@ -27,6 +36,8 @@ var RouteCache = class {
27
36
  if (this.storage === "memory" || !this.backend) {
28
37
  return this.getFromMemory(level);
29
38
  }
39
+ const mirrored = this.getFromMemory(level);
40
+ if (mirrored) return mirrored;
30
41
  const raw = this.backend.getItem(this.key(level));
31
42
  if (raw) {
32
43
  try {
@@ -35,12 +46,13 @@ var RouteCache = class {
35
46
  this.del(level);
36
47
  return void 0;
37
48
  }
49
+ this.memory.set(level, entry);
38
50
  return entry;
39
51
  } catch {
40
52
  return void 0;
41
53
  }
42
54
  }
43
- return this.getFromMemory(level);
55
+ return void 0;
44
56
  }
45
57
  getFromMemory(level) {
46
58
  const entry = this.memory.get(level);
@@ -64,14 +76,13 @@ var RouteCache = class {
64
76
  ttl,
65
77
  cachedAt: Date.now()
66
78
  };
79
+ this.memory.set(resp.level, entry);
67
80
  if (this.storage === "memory" || !this.backend) {
68
- this.memory.set(resp.level, entry);
69
81
  return;
70
82
  }
71
83
  try {
72
84
  this.backend.setItem(this.key(resp.level), JSON.stringify(entry));
73
85
  } catch {
74
- this.memory.set(resp.level, entry);
75
86
  }
76
87
  }
77
88
  del(level) {
@@ -251,14 +262,14 @@ function createInterceptorManager() {
251
262
  return new InterceptorManagerImpl();
252
263
  }
253
264
 
254
- // src/adapters/builtin-http.ts
255
- function isPassthroughBody(body) {
256
- if (body === null) return false;
257
- 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;
258
- }
259
- function isAbortError(err) {
265
+ // src/adapters/fetch-core.ts
266
+ function isAbortError(err, signal) {
267
+ if (signal?.aborted) return true;
260
268
  const e = err;
261
- return !!e && e.name === "AbortError";
269
+ if (!e) return false;
270
+ if (e.name === "AbortError") return true;
271
+ if (e.code === "ERR_CANCELED") return true;
272
+ return false;
262
273
  }
263
274
  function combineSignals(...signals) {
264
275
  const valid = signals.filter((s) => !!s);
@@ -277,81 +288,92 @@ function combineSignals(...signals) {
277
288
  }
278
289
  return controller.signal;
279
290
  }
280
- function createBuiltinHttp(forgeInterceptors) {
281
- const requestMgr = forgeInterceptors?.request ?? createInterceptorManager();
282
- const responseMgr = forgeInterceptors?.response ?? createInterceptorManager();
283
- async function request(config) {
284
- const finalConfig = await runRequestInterceptors(requestMgr, config);
285
- const signal = combineSignals(
286
- finalConfig.signal,
287
- finalConfig.timeout && finalConfig.timeout > 0 ? AbortSignal.timeout(finalConfig.timeout) : void 0
288
- );
289
- let url = finalConfig.url;
290
- if (finalConfig.paramsSerializer && finalConfig.params) {
291
- const qs = finalConfig.paramsSerializer(finalConfig.params);
292
- if (qs) {
293
- url = url.includes("?") ? `${url}&${qs}` : `${url}?${qs}`;
294
- }
291
+ function isPassthroughBody(body) {
292
+ if (body === null) return false;
293
+ 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;
294
+ }
295
+ async function rawFetch(config) {
296
+ const signal = combineSignals(
297
+ config.signal,
298
+ config.timeout && config.timeout > 0 ? AbortSignal.timeout(config.timeout) : void 0
299
+ );
300
+ let url = config.url;
301
+ if (config.paramsSerializer && config.params) {
302
+ const qs = config.paramsSerializer(config.params);
303
+ if (qs) {
304
+ url = url.includes("?") ? `${url}&${qs}` : `${url}?${qs}`;
295
305
  }
296
- const headers = new Headers(finalConfig.headers);
297
- const fetchInit = {
298
- method: finalConfig.method,
299
- headers
300
- };
301
- if (signal) fetchInit.signal = signal;
302
- if (finalConfig.body !== void 0 && !["GET", "HEAD"].includes(finalConfig.method.toUpperCase())) {
303
- if (typeof finalConfig.body === "string" || isPassthroughBody(finalConfig.body)) {
304
- fetchInit.body = finalConfig.body;
305
- } else {
306
- fetchInit.body = JSON.stringify(finalConfig.body);
307
- if (!headers.has("Content-Type")) {
308
- headers.set("Content-Type", "application/json");
309
- }
306
+ }
307
+ const headers = new Headers(config.headers);
308
+ const fetchInit = {
309
+ method: config.method,
310
+ headers
311
+ };
312
+ if (signal) fetchInit.signal = signal;
313
+ if (config.body !== void 0 && !["GET", "HEAD"].includes(config.method.toUpperCase())) {
314
+ if (typeof config.body === "string" || isPassthroughBody(config.body)) {
315
+ fetchInit.body = config.body;
316
+ } else {
317
+ fetchInit.body = JSON.stringify(config.body);
318
+ if (!headers.has("Content-Type")) {
319
+ headers.set("Content-Type", "application/json");
310
320
  }
311
321
  }
312
- let res;
322
+ }
323
+ let res;
324
+ try {
325
+ res = await fetch(url, fetchInit);
326
+ } catch (e) {
327
+ if (isAbortError(e)) throw e;
328
+ throw new NetworkError(
329
+ e instanceof Error ? e.message : String(e),
330
+ config.route,
331
+ config.level,
332
+ e
333
+ );
334
+ }
335
+ const text = await res.text();
336
+ let data = text;
337
+ const contentType = res.headers.get("content-type") ?? "";
338
+ if (contentType.includes("application/json")) {
313
339
  try {
314
- res = await fetch(url, fetchInit);
315
- } catch (e) {
316
- if (isAbortError(e)) throw e;
317
- throw new NetworkError(
318
- e instanceof Error ? e.message : String(e),
319
- finalConfig.route,
320
- finalConfig.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
- }
340
+ data = JSON.parse(text);
341
+ } catch {
332
342
  }
333
- const responseData = {
334
- route: finalConfig.route,
335
- level: finalConfig.level,
336
- method: finalConfig.method,
337
- url,
343
+ }
344
+ const responseData = {
345
+ route: config.route,
346
+ level: config.level,
347
+ method: config.method,
348
+ url,
349
+ status: res.status,
350
+ headers: res.headers,
351
+ data,
352
+ config
353
+ };
354
+ if (res.status >= 200 && res.status < 300) {
355
+ return responseData;
356
+ }
357
+ throw new HTTPError(
358
+ `HTTP ${res.status} for route "${config.route}" (${config.method} ${url})`,
359
+ {
360
+ route: config.route,
361
+ level: config.level,
338
362
  status: res.status,
339
- headers: res.headers,
340
- data,
341
- config: finalConfig
342
- };
343
- const source = res.status >= 200 && res.status < 300 ? Promise.resolve(responseData) : Promise.reject(
344
- new HTTPError(
345
- `HTTP ${res.status} for route "${finalConfig.route}" (${finalConfig.method} ${url})`,
346
- {
347
- route: finalConfig.route,
348
- level: finalConfig.level,
349
- status: res.status,
350
- url,
351
- method: finalConfig.method
352
- }
353
- )
354
- );
363
+ url,
364
+ method: config.method
365
+ }
366
+ );
367
+ }
368
+
369
+ // src/adapters/builtin-http.ts
370
+ function createBuiltinHttp(forgeInterceptors) {
371
+ const requestMgr = forgeInterceptors?.request ?? createInterceptorManager();
372
+ const responseMgr = forgeInterceptors?.response ?? createInterceptorManager();
373
+ const requestRaw = rawFetch;
374
+ async function request(config) {
375
+ const finalConfig = await runRequestInterceptors(requestMgr, config);
376
+ const source = Promise.resolve(finalConfig).then(requestRaw);
355
377
  return runResponseInterceptors(
356
378
  responseMgr,
357
379
  source
@@ -364,6 +386,7 @@ function createBuiltinHttp(forgeInterceptors) {
364
386
  const del = (url, config) => request({ ...config, url, method: "DELETE" });
365
387
  return {
366
388
  request,
389
+ requestRaw,
367
390
  interceptors: {
368
391
  request: requestMgr,
369
392
  response: responseMgr
@@ -575,7 +598,6 @@ function createRouteForge(options) {
575
598
  const loadingTracker = new LoadingTracker();
576
599
  const explicitLevels = options.levels;
577
600
  const explicitEager = options.eager;
578
- const explicitStrict = options.strict ?? false;
579
601
  const explicitEndpoint = options.endpoint;
580
602
  let effectiveLevels = explicitLevels ?? [];
581
603
  let effectiveEager = explicitEager ?? [];
@@ -583,17 +605,12 @@ function createRouteForge(options) {
583
605
  let effectiveUrlPrefix = "";
584
606
  let summaryUnassigned;
585
607
  let backendHasUnassignedLevel = false;
586
- const summaryPromise = (async () => {
608
+ const fetchSummary = async () => {
587
609
  try {
588
- const summaryUrl = explicitEndpoint;
589
- const resp = await fetch(summaryUrl, { method: "GET" });
590
- if (!resp.ok) {
591
- console.warn(
592
- `[route-forge] summary endpoint ${summaryUrl} unreachable (HTTP ${resp.status}); falling back to explicit options`
593
- );
594
- return null;
595
- }
596
- return await resp.json();
610
+ const base = baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL;
611
+ const ep = explicitEndpoint.startsWith("/") ? explicitEndpoint : `/${explicitEndpoint}`;
612
+ const data = await fetchMeta("__forge__.summary", `${base}${ep}`);
613
+ return data;
597
614
  } catch (e) {
598
615
  if (explicitLevels && explicitLevels.length > 0) {
599
616
  console.warn(
@@ -603,8 +620,11 @@ function createRouteForge(options) {
603
620
  }
604
621
  throw new UnknownLevelError("(auto-discovery)");
605
622
  }
606
- })();
607
- const autoDiscoveryPromise = summaryPromise.then((summary) => {
623
+ };
624
+ let summaryPromise;
625
+ const summaryWaiters = [];
626
+ const whenSummary = () => summaryPromise ?? new Promise((resolve) => summaryWaiters.push(resolve));
627
+ const autoDiscoveryPromise = whenSummary().then((summary) => {
608
628
  if (summary === null) {
609
629
  return;
610
630
  }
@@ -623,11 +643,6 @@ function createRouteForge(options) {
623
643
  if (summary.config.url_prefix) {
624
644
  effectiveUrlPrefix = summary.config.url_prefix.endsWith("/") ? summary.config.url_prefix.slice(0, -1) : summary.config.url_prefix;
625
645
  }
626
- if (summary.config.strict_mode && !explicitStrict) {
627
- console.warn(
628
- "[route-forge] backend strict_mode=true overrides frontend strict=false; forcing strict=true"
629
- );
630
- }
631
646
  const backendLevels = Object.keys(summary.levels);
632
647
  backendHasUnassignedLevel = backendLevels.includes(UNASSIGNED_LEVEL);
633
648
  if (Array.isArray(summary.unassigned) && summary.unassigned.length > 0 && !backendHasUnassignedLevel) {
@@ -663,8 +678,12 @@ function createRouteForge(options) {
663
678
  });
664
679
  let autoDiscoveryCompleted = false;
665
680
  let resolveReady;
666
- const readyPromise = new Promise((resolve) => {
681
+ let rejectReady;
682
+ const readyPromise = new Promise((resolve, reject) => {
667
683
  resolveReady = resolve;
684
+ rejectReady = reject;
685
+ });
686
+ readyPromise.catch(() => {
668
687
  });
669
688
  const cacheTtl = cacheOpts.ttl ?? DEFAULT_CACHE_TTL;
670
689
  const cacheStorage = cacheOpts.storage ?? "memory";
@@ -695,13 +714,20 @@ function createRouteForge(options) {
695
714
  adapter,
696
715
  forgeInterceptors: { request: requestInterceptors, response: responseInterceptors }
697
716
  });
717
+ Promise.resolve().then(() => {
718
+ summaryPromise = fetchSummary();
719
+ for (const resolve of summaryWaiters) resolve(summaryPromise);
720
+ });
698
721
  let adapterResolved = false;
699
722
  let adapterObj = null;
700
723
  async function ensureAdapter() {
701
724
  if (!adapterResolved) {
702
725
  adapterObj = await adapterPromise.catch((e) => {
703
726
  if (e instanceof AdapterNotFoundError) throw e;
704
- return resolveAdapter({ adapter: "builtin" });
727
+ return resolveAdapter({
728
+ adapter: "builtin",
729
+ forgeInterceptors: { request: requestInterceptors, response: responseInterceptors }
730
+ });
705
731
  });
706
732
  adapterResolved = true;
707
733
  }
@@ -727,33 +753,36 @@ function createRouteForge(options) {
727
753
  const ep = effectiveEndpoint.startsWith("/") ? effectiveEndpoint : `/${effectiveEndpoint}`;
728
754
  return `${base}${ep}/${encodeURIComponent(level)}`;
729
755
  }
730
- async function fetchLevel(level) {
756
+ async function fetchMeta(routeTag, url, level = "") {
731
757
  const adp = await ensureAdapter();
732
758
  const config = {
733
- route: `__forge__.load.${level}`,
759
+ route: routeTag,
734
760
  level,
735
761
  method: "GET",
736
- url: buildUrl(level),
762
+ url,
737
763
  headers: { Accept: "application/json" },
738
764
  params: {},
739
765
  timeout,
740
766
  meta: {
741
- name: `__forge__.load.${level}`,
742
- uri: buildUrl(level),
767
+ name: routeTag,
768
+ uri: url,
743
769
  methods: ["GET"],
744
770
  parameters: [],
745
771
  level
746
772
  }
747
773
  };
748
- const resp = await adp.request(config);
774
+ const doRawRequest = adp.requestRaw ?? adp.request;
775
+ const resp = await doRawRequest(config);
749
776
  if (!resp || resp.status < 200 || resp.status >= 300) {
750
777
  throw new HTTPError(
751
- `Failed to load level "${level}": HTTP ${resp?.status}`,
752
- { level, status: resp?.status, url: buildUrl(level), method: "GET" }
778
+ `Failed to fetch "${routeTag}": HTTP ${resp?.status}`,
779
+ { level, status: resp?.status, url, method: "GET" }
753
780
  );
754
781
  }
755
- const data = resp.data;
756
- return data;
782
+ return resp.data;
783
+ }
784
+ async function fetchLevel(level) {
785
+ return await fetchMeta(`__forge__.load.${level}`, buildUrl(level), level);
757
786
  }
758
787
  async function loadOne(level) {
759
788
  if (autoDiscoveryError) throw autoDiscoveryError;
@@ -925,7 +954,7 @@ function createRouteForge(options) {
925
954
  },
926
955
  (err) => {
927
956
  if (err instanceof ForgeError) throw err;
928
- if (isAbortError2(err, signal)) {
957
+ if (isAbortError(err, signal)) {
929
958
  throw new RequestAbortedError(meta.name, meta.level, err);
930
959
  }
931
960
  throw new NetworkError(
@@ -994,15 +1023,22 @@ function createRouteForge(options) {
994
1023
  }
995
1024
  void autoDiscoveryPromise.then(() => {
996
1025
  autoDiscoveryCompleted = true;
997
- options.onSummaryReady?.();
998
1026
  if (effectiveEager.length > 0) {
999
- return Promise.all(effectiveEager.map((lvl) => load(lvl))).catch((e) => {
1000
- console.warn(`[route-forge] eager load failed: ${e.message}`);
1027
+ return Promise.allSettled(effectiveEager.map((lvl) => load(lvl))).then((results) => {
1028
+ results.forEach((r, i) => {
1029
+ if (r.status === "rejected") {
1030
+ console.error(
1031
+ `[route-forge] eager load failed for level "${effectiveEager[i]}":`,
1032
+ r.reason
1033
+ );
1034
+ }
1035
+ });
1001
1036
  });
1002
1037
  }
1003
1038
  }).then(() => {
1004
1039
  resolveReady(forgeInstance);
1005
- }).catch(() => {
1040
+ }).catch((e) => {
1041
+ rejectReady(e);
1006
1042
  });
1007
1043
  function ready(onFulfilled, onRejected) {
1008
1044
  if (onFulfilled) {
@@ -1013,7 +1049,8 @@ function createRouteForge(options) {
1013
1049
  }
1014
1050
  const forgeResolver = { load, hasRoute };
1015
1051
  function createBoundForge(level, prefix) {
1016
- const levelLoadedPromise = load(level).catch(() => {
1052
+ const levelLoadedPromise = load(level);
1053
+ levelLoadedPromise.catch(() => {
1017
1054
  });
1018
1055
  const apiFn = prefix ? (name, params) => resolveRouteName(forgeResolver, level, prefix, name).then(
1019
1056
  (resolved) => api(level, resolved, params)
@@ -1147,14 +1184,6 @@ function resolveApiParams(input) {
1147
1184
  }
1148
1185
  return { pathParams, query, body, headers, timeout: perCallTimeout };
1149
1186
  }
1150
- function isAbortError2(err, signal) {
1151
- if (signal?.aborted) return true;
1152
- const e = err;
1153
- if (!e) return false;
1154
- if (e.name === "AbortError") return true;
1155
- if (e.code === "ERR_CANCELED") return true;
1156
- return false;
1157
- }
1158
1187
 
1159
1188
  exports.AdapterNotFoundError = AdapterNotFoundError;
1160
1189
  exports.ForgeError = ForgeError;