@route-forge/core 2.0.0 → 2.2.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/dist/index.js CHANGED
@@ -61,12 +61,28 @@ var RouteCache = class {
61
61
  }
62
62
  return entry;
63
63
  }
64
- set(resp) {
64
+ /**
65
+ * 写入某层级缓存。后端 TTL 唯一来源为摘要 config.cache_ttl(全局),经参数 backendTtl 传入:
66
+ * - null → 后端声明"不缓存":不写 storage,仅留内存镜像供 route() 同步读(load 层"每次重取"由调用方跳过 get 短路实现)
67
+ * - 0 → 永久缓存(内存 + storage)
68
+ * - undefined → 后端未下发该字段:用前端兜底 TTL(options.cache.ttl)
69
+ * - 正整数 → min(后端, 前端兜底):后端为上限,前端只能缩短不能延长(SPEC §5.3)
70
+ */
71
+ set(resp, backendTtl) {
65
72
  let ttl;
66
- if (resp.cache !== void 0 && resp.cache !== null) {
67
- ttl = resp.cache > 0 ? Math.min(resp.cache, this.fallbackTtl) : resp.cache;
68
- } else {
73
+ let persist;
74
+ if (backendTtl === null) {
75
+ ttl = 0;
76
+ persist = false;
77
+ } else if (backendTtl === void 0) {
69
78
  ttl = this.fallbackTtl;
79
+ persist = true;
80
+ } else if (backendTtl === 0) {
81
+ ttl = 0;
82
+ persist = true;
83
+ } else {
84
+ ttl = Math.min(backendTtl, this.fallbackTtl);
85
+ persist = true;
70
86
  }
71
87
  const entry = {
72
88
  level: resp.level,
@@ -75,7 +91,7 @@ var RouteCache = class {
75
91
  cachedAt: Date.now()
76
92
  };
77
93
  this.memory.set(resp.level, entry);
78
- if (this.storage === "memory" || !this.backend) {
94
+ if (!persist || this.storage === "memory" || !this.backend) {
79
95
  return;
80
96
  }
81
97
  try {
@@ -488,39 +504,6 @@ async function resolveAdapter(opts) {
488
504
  return createBuiltinHttp(opts.forgeInterceptors);
489
505
  }
490
506
 
491
- // src/resolveRouteName.ts
492
- async function resolveRouteName(forge, level, prefix, suffix, separator = ".") {
493
- if (!suffix) return prefix;
494
- const joined = `${prefix}${separator}${suffix}`;
495
- if (!suffix.startsWith(`${prefix}${separator}`)) return joined;
496
- await forge.load(level);
497
- if (forge.hasRoute(level, joined)) return joined;
498
- if (forge.hasRoute(level, suffix)) return suffix;
499
- throw new UnknownRouteError(joined, level);
500
- }
501
- function resolveRouteNameSync(forge, level, prefix, suffix, separator = ".") {
502
- if (!suffix) return prefix;
503
- const joined = `${prefix}${separator}${suffix}`;
504
- if (!suffix.startsWith(`${prefix}${separator}`)) return joined;
505
- if (forge.hasRoute(level, joined)) return joined;
506
- if (forge.hasRoute(level, suffix)) return suffix;
507
- throw new UnknownRouteError(joined, level);
508
- }
509
-
510
- // src/defineImmutableProps.ts
511
- function defineImmutableProps(target, props) {
512
- for (const key of Object.keys(props)) {
513
- const val = props[key];
514
- Object.defineProperty(target, key, {
515
- value: val !== null && typeof val === "object" ? Object.freeze(val) : val,
516
- writable: false,
517
- enumerable: false,
518
- configurable: false
519
- });
520
- }
521
- return target;
522
- }
523
-
524
507
  // src/loading.ts
525
508
  var LoadingTracker = class {
526
509
  constructor() {
@@ -580,328 +563,333 @@ var LoadingTracker = class {
580
563
  }
581
564
  };
582
565
 
583
- // src/forge.ts
584
- var DEFAULT_TIMEOUT = 3e4;
585
- var DEFAULT_CACHE_TTL = 3600;
586
- var UNASSIGNED_LEVEL = "unassigned";
587
- function createRouteForge(options) {
588
- if (!options.endpoint) throw new TypeError("options.endpoint is required");
589
- const {
590
- adapter = "auto",
591
- timeout = DEFAULT_TIMEOUT,
592
- baseURL = "",
593
- interceptors: declarativeInterceptors,
594
- cache: cacheOpts = {}
595
- } = options;
596
- const loadingTracker = new LoadingTracker();
597
- const explicitLevels = options.levels;
598
- const explicitEager = options.eager;
599
- const explicitEndpoint = options.endpoint;
600
- let effectiveLevels = explicitLevels ?? [];
601
- let effectiveEager = explicitEager ?? [];
602
- let effectiveEndpoint = explicitEndpoint;
603
- let effectiveUrlPrefix = "";
604
- let summaryUnassigned;
605
- let backendHasUnassignedLevel = false;
606
- const fetchSummary = async () => {
607
- try {
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;
612
- } catch (e) {
613
- if (explicitLevels && explicitLevels.length > 0) {
614
- console.warn(
615
- `[route-forge] summary endpoint unreachable: ${e.message}; using explicit levels`
616
- );
617
- return null;
618
- }
619
- throw new UnknownLevelError("(auto-discovery)");
620
- }
621
- };
622
- let summaryPromise;
623
- const summaryWaiters = [];
624
- const whenSummary = () => summaryPromise ?? new Promise((resolve) => summaryWaiters.push(resolve));
625
- const autoDiscoveryPromise = whenSummary().then((summary) => {
626
- if (summary === null) {
627
- return;
628
- }
629
- const schemaVersion = summary.schemaVersion ?? 1;
630
- if (schemaVersion > 1) {
631
- console.warn(
632
- `[route-forge] backend schemaVersion=${schemaVersion} > client supported 1; some features may be unavailable`
633
- );
634
- }
635
- if (summary.config.endpoint_prefix && summary.config.endpoint_prefix !== explicitEndpoint) {
636
- console.warn(
637
- `[route-forge] backend endpoint_prefix "${summary.config.endpoint_prefix}" overrides frontend endpoint "${explicitEndpoint}"`
638
- );
639
- effectiveEndpoint = summary.config.endpoint_prefix;
640
- }
641
- if (summary.config.url_prefix) {
642
- effectiveUrlPrefix = summary.config.url_prefix.endsWith("/") ? summary.config.url_prefix.slice(0, -1) : summary.config.url_prefix;
643
- }
644
- const backendLevels = Object.keys(summary.levels);
645
- backendHasUnassignedLevel = backendLevels.includes(UNASSIGNED_LEVEL);
646
- if (Array.isArray(summary.unassigned) && summary.unassigned.length > 0 && !backendHasUnassignedLevel) {
647
- summaryUnassigned = summary.unassigned;
648
- }
649
- const availableLevels = backendLevels.slice();
650
- if (summaryUnassigned && !backendHasUnassignedLevel) {
651
- availableLevels.push(UNASSIGNED_LEVEL);
566
+ // src/url-builder.ts
567
+ function buildUrl(level, ctx) {
568
+ const base = ctx.baseURL.endsWith("/") ? ctx.baseURL.slice(0, -1) : ctx.baseURL;
569
+ const ep = ctx.endpoint.startsWith("/") ? ctx.endpoint : `/${ctx.endpoint}`;
570
+ return `${base}${ep}/${encodeURIComponent(level)}`;
571
+ }
572
+ function buildRequestUrl(meta, params, ctx) {
573
+ const defaults = meta.parameter_defaults ?? {};
574
+ const missingRequired = [];
575
+ const values = {};
576
+ for (const p of meta.parameters) {
577
+ let v = params[p];
578
+ if ((v === void 0 || v === null) && p in defaults) {
579
+ v = defaults[p];
652
580
  }
653
- if (explicitLevels && explicitLevels.length > 0) {
654
- const intersection = explicitLevels.filter((l) => availableLevels.includes(l));
655
- const removed = explicitLevels.filter((l) => !availableLevels.includes(l));
656
- if (removed.length > 0) {
657
- console.warn(
658
- `[route-forge] levels not in backend summary and dropped: ${removed.join(", ")}`
659
- );
581
+ if (v === void 0 || v === null) {
582
+ if (!meta.uri.includes(`{${p}?}`)) {
583
+ missingRequired.push(p);
660
584
  }
661
- effectiveLevels = intersection;
662
585
  } else {
663
- effectiveLevels = availableLevels;
586
+ values[p] = v;
664
587
  }
665
- const backendEager = backendLevels.filter((lvl) => summary.levels[lvl]?.load === "eager");
666
- if (!explicitEager) {
667
- effectiveEager = backendEager;
668
- } else {
669
- const union = /* @__PURE__ */ new Set([...backendEager, ...explicitEager]);
670
- effectiveEager = [...union];
588
+ }
589
+ if (missingRequired.length > 0) {
590
+ throw new MissingRouteParamError(meta.name, missingRequired);
591
+ }
592
+ let uri = meta.uri.replace(/\{([^{}]+)\}/g, (match, raw) => {
593
+ const optional = raw.endsWith("?");
594
+ const name = optional ? raw.slice(0, -1) : raw;
595
+ if (values[name] !== void 0) {
596
+ const val = values[name];
597
+ if (typeof val === "object") {
598
+ throw new ForgeError(
599
+ `Path parameter "${name}" must be a primitive value (string, number, boolean), got ${typeof val}`,
600
+ { code: "RF_FE_003", route: meta.name, context: { param: name, value: val } }
601
+ );
602
+ }
603
+ return encodeURIComponent(String(val));
671
604
  }
605
+ return optional ? "" : match;
672
606
  });
673
- let autoDiscoveryError = null;
674
- autoDiscoveryPromise.catch((e) => {
675
- autoDiscoveryError = e;
676
- });
677
- let autoDiscoveryCompleted = false;
678
- let resolveReady;
679
- let rejectReady;
680
- const readyPromise = new Promise((resolve, reject) => {
681
- resolveReady = resolve;
682
- rejectReady = reject;
683
- });
684
- readyPromise.catch(() => {
685
- });
686
- const cacheTtl = cacheOpts.ttl ?? DEFAULT_CACHE_TTL;
687
- const cacheStorage = cacheOpts.storage ?? "memory";
688
- const cache = new RouteCache({ storage: cacheStorage, ttl: cacheTtl });
689
- const requestInterceptors = new InterceptorManagerImpl();
690
- const responseInterceptors = new InterceptorManagerImpl();
691
- if (declarativeInterceptors?.request) {
692
- for (const entry of declarativeInterceptors.request) {
693
- if (typeof entry === "function") {
694
- requestInterceptors.use(entry);
695
- } else {
696
- const [onFulfilled, onRejected] = entry;
697
- requestInterceptors.use(onFulfilled, onRejected);
698
- }
607
+ uri = uri.replace(/\/+/g, "/").replace(/\/$/, "");
608
+ if (/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(ctx.urlPrefix)) {
609
+ const prefix2 = ctx.urlPrefix.endsWith("/") ? ctx.urlPrefix.slice(0, -1) : ctx.urlPrefix;
610
+ return uri.startsWith("/") ? `${prefix2}${uri}` : `${prefix2}/${uri}`;
611
+ }
612
+ const base = ctx.baseURL.endsWith("/") ? ctx.baseURL.slice(0, -1) : ctx.baseURL;
613
+ const prefix = ctx.urlPrefix;
614
+ return uri.startsWith("/") ? `${base}${prefix}${uri}` : `${base}${prefix}/${uri}`;
615
+ }
616
+ function pickMethod(meta) {
617
+ const m = meta.methods.find((x) => x.toUpperCase() !== "HEAD");
618
+ return (m ?? meta.methods[0] ?? "GET").toUpperCase();
619
+ }
620
+ function appendQuery(url, query) {
621
+ if (!query) return url;
622
+ const usp = new URLSearchParams();
623
+ for (const [k, v] of Object.entries(query)) {
624
+ if (v === void 0 || v === null) continue;
625
+ usp.append(k, String(v));
626
+ }
627
+ const qs = usp.toString();
628
+ if (!qs) return url;
629
+ return url.includes("?") ? `${url}&${qs}` : `${url}?${qs}`;
630
+ }
631
+ function resolveApiParams(input) {
632
+ const {
633
+ params: explicitParams,
634
+ query: rawQuery,
635
+ body: rawBody,
636
+ headers: rawHeaders,
637
+ timeout: perCallTimeout,
638
+ ...flatRest
639
+ } = input;
640
+ const pathParams = explicitParams ? { ...explicitParams } : {};
641
+ for (const [k, v] of Object.entries(flatRest)) {
642
+ if (!(k in pathParams)) {
643
+ pathParams[k] = v;
699
644
  }
700
645
  }
701
- if (declarativeInterceptors?.response) {
702
- for (const entry of declarativeInterceptors.response) {
703
- if (typeof entry === "function") {
704
- responseInterceptors.use(entry);
705
- } else {
706
- const [onFulfilled, onRejected] = entry;
707
- responseInterceptors.use(onFulfilled, onRejected);
708
- }
646
+ let query;
647
+ let body;
648
+ let headers;
649
+ if (rawQuery !== void 0) {
650
+ if (typeof rawQuery === "object" && rawQuery !== null) {
651
+ query = rawQuery;
652
+ } else if (!("query" in pathParams)) {
653
+ pathParams.query = rawQuery;
709
654
  }
710
655
  }
711
- const adapterPromise = resolveAdapter({
712
- adapter,
713
- forgeInterceptors: { request: requestInterceptors, response: responseInterceptors }
714
- });
715
- Promise.resolve().then(() => {
716
- summaryPromise = fetchSummary();
717
- for (const resolve of summaryWaiters) resolve(summaryPromise);
718
- });
719
- let adapterResolved = false;
720
- let adapterObj = null;
721
- async function ensureAdapter() {
722
- if (!adapterResolved) {
723
- adapterObj = await adapterPromise.catch((e) => {
724
- if (e instanceof AdapterNotFoundError) throw e;
725
- return resolveAdapter({
726
- adapter: "builtin",
727
- forgeInterceptors: { request: requestInterceptors, response: responseInterceptors }
728
- });
729
- });
730
- adapterResolved = true;
656
+ if (rawBody !== void 0) {
657
+ if (typeof rawBody !== "string" && typeof rawBody !== "number") {
658
+ body = rawBody;
659
+ } else if (!("body" in pathParams)) {
660
+ pathParams.body = rawBody;
731
661
  }
732
- return adapterObj;
733
662
  }
734
- const inflight = /* @__PURE__ */ new Map();
735
- const invalidationGens = /* @__PURE__ */ new Map();
736
- function assertLevelDeclared(level) {
737
- if (!effectiveLevels.includes(level)) {
738
- throw new UnknownLevelError(level);
663
+ if (rawHeaders !== void 0) {
664
+ if (typeof rawHeaders === "object" && rawHeaders !== null) {
665
+ headers = rawHeaders;
666
+ } else if (!("headers" in pathParams)) {
667
+ pathParams.headers = rawHeaders;
739
668
  }
740
669
  }
741
- function assertDiscoveryReady() {
742
- if (!autoDiscoveryCompleted && !explicitLevels?.length) {
743
- throw new ForgeError(
744
- "Route data not available. Auto-discovery has not completed. Use forge.ready() or forge.use(level) first.",
745
- { code: "RF_FE_010" }
670
+ return { pathParams, query, body, headers, timeout: perCallTimeout };
671
+ }
672
+
673
+ // src/auto-discovery.ts
674
+ async function fetchSummary(inputs, baseURL, fetchMeta) {
675
+ const { explicitLevels, explicitEndpoint } = inputs;
676
+ if (!explicitEndpoint) {
677
+ throw new UnknownLevelError("(auto-discovery)");
678
+ }
679
+ try {
680
+ const base = baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL;
681
+ const ep = explicitEndpoint.startsWith("/") ? explicitEndpoint : `/${explicitEndpoint}`;
682
+ const data = await fetchMeta("__forge__.summary", `${base}${ep}`);
683
+ return data;
684
+ } catch (e) {
685
+ if (explicitLevels && explicitLevels.length > 0) {
686
+ console.warn(
687
+ `[route-forge] summary endpoint unreachable: ${e.message}; using explicit levels`
746
688
  );
689
+ return null;
747
690
  }
691
+ throw new UnknownLevelError("(auto-discovery)");
748
692
  }
749
- function buildUrl(level) {
750
- const base = baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL;
751
- const ep = effectiveEndpoint.startsWith("/") ? effectiveEndpoint : `/${effectiveEndpoint}`;
752
- return `${base}${ep}/${encodeURIComponent(level)}`;
693
+ }
694
+ function normalizeCacheTtl(raw) {
695
+ if (typeof raw === "number" && raw < 0) return null;
696
+ return raw;
697
+ }
698
+ function applySummaryToState(summary, state, inputs) {
699
+ const { explicitLevels, explicitEager, explicitEndpoint } = inputs;
700
+ const schemeVersion = summary.schemeVersion ?? 1;
701
+ if (schemeVersion > 1) {
702
+ console.warn(
703
+ `[route-forge] backend schemeVersion=${schemeVersion} > client supported 1; some features may be unavailable`
704
+ );
753
705
  }
754
- async function fetchMeta(routeTag, url, level = "") {
755
- const adp = await ensureAdapter();
756
- const config = {
757
- route: routeTag,
758
- level,
759
- method: "GET",
760
- url,
761
- headers: { Accept: "application/json" },
762
- params: {},
763
- timeout,
764
- meta: {
765
- name: routeTag,
766
- uri: url,
767
- methods: ["GET"],
768
- parameters: [],
769
- level
770
- }
771
- };
772
- const doRawRequest = adp.requestRaw ?? adp.request;
773
- const resp = await doRawRequest(config);
774
- if (!resp || resp.status < 200 || resp.status >= 300) {
775
- throw new HTTPError(
776
- `Failed to fetch "${routeTag}": HTTP ${resp?.status}`,
777
- { level, status: resp?.status, url, method: "GET" }
706
+ if (summary.config.endpoint_prefix && summary.config.endpoint_prefix !== explicitEndpoint) {
707
+ if (explicitEndpoint) {
708
+ console.warn(
709
+ `[route-forge] backend endpoint_prefix "${summary.config.endpoint_prefix}" overrides frontend endpoint "${explicitEndpoint}"`
778
710
  );
779
711
  }
780
- return resp.data;
712
+ state.endpoint = summary.config.endpoint_prefix;
713
+ }
714
+ if (summary.config.url_prefix) {
715
+ state.urlPrefix = summary.config.url_prefix.endsWith("/") ? summary.config.url_prefix.slice(0, -1) : summary.config.url_prefix;
716
+ }
717
+ state.cacheTtl = normalizeCacheTtl(summary.config.cache_ttl);
718
+ const backendLevels = Object.keys(summary.levels);
719
+ const levelRoutes = {};
720
+ for (const lvl of backendLevels) {
721
+ const r = summary.levels[lvl]?.route;
722
+ if (r && typeof r.uri === "string") {
723
+ levelRoutes[lvl] = { uri: r.uri, methods: r.methods ?? ["GET", "HEAD"] };
724
+ }
725
+ }
726
+ state.levelRoutes = levelRoutes;
727
+ if (explicitLevels && explicitLevels.length > 0) {
728
+ const intersection = explicitLevels.filter((l) => backendLevels.includes(l));
729
+ const removed = explicitLevels.filter((l) => !backendLevels.includes(l));
730
+ if (removed.length > 0) {
731
+ console.warn(
732
+ `[route-forge] levels not in backend summary and dropped: ${removed.join(", ")}`
733
+ );
734
+ }
735
+ state.levels = intersection;
736
+ } else {
737
+ state.levels = backendLevels.slice();
738
+ }
739
+ const backendEager = backendLevels.filter((lvl) => summary.levels[lvl]?.load === "eager");
740
+ if (!explicitEager) {
741
+ state.eager = backendEager;
742
+ } else {
743
+ const union = /* @__PURE__ */ new Set([...backendEager, ...explicitEager]);
744
+ state.eager = [...union];
745
+ }
746
+ }
747
+
748
+ // src/embedded-summary.ts
749
+ var EMBEDDED_GLOBAL_KEY = "__ROUTE_FORGE__";
750
+ var memo;
751
+ function readEmbeddedSummary() {
752
+ if (memo !== void 0) return memo;
753
+ if (typeof window === "undefined") {
754
+ memo = null;
755
+ return null;
756
+ }
757
+ let raw;
758
+ try {
759
+ raw = window[EMBEDDED_GLOBAL_KEY];
760
+ } catch {
761
+ raw = void 0;
762
+ }
763
+ memo = raw !== null && typeof raw === "object" ? raw : null;
764
+ return memo;
765
+ }
766
+
767
+ // src/route-store.ts
768
+ var RouteStore = class {
769
+ constructor(deps) {
770
+ this.inflight = /* @__PURE__ */ new Map();
771
+ /** 每个层级的失效代数,用于检测 loadOne 期间是否发生了 invalidate */
772
+ this.invalidationGens = /* @__PURE__ */ new Map();
773
+ this.cache = deps.cache;
774
+ this.state = deps.state;
775
+ this.baseURL = deps.baseURL;
776
+ this.fetchMeta = deps.fetchMeta;
777
+ this.autoDiscoveryPromise = deps.autoDiscoveryPromise;
778
+ this.getAutoDiscoveryError = deps.getAutoDiscoveryError;
779
+ }
780
+ assertLevelDeclared(level) {
781
+ if (!this.state.levels.includes(level)) {
782
+ throw new UnknownLevelError(level);
783
+ }
781
784
  }
782
- async function fetchLevel(level) {
783
- return await fetchMeta(`__forge__.load.${level}`, buildUrl(level), level);
785
+ async fetchLevel(level) {
786
+ const uri = this.state.levelRoutes[level]?.uri;
787
+ const url = uri ? this.joinBaseAndPath(this.baseURL, uri) : buildUrl(level, { baseURL: this.baseURL, endpoint: this.state.endpoint });
788
+ return await this.fetchMeta(`route-forge.${level}`, url, level);
789
+ }
790
+ /** baseURL 与后端下发的绝对 path 拼接(规范化斜杠),与 buildUrl 的 base 处理一致 */
791
+ joinBaseAndPath(baseURL, path) {
792
+ const base = baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL;
793
+ const p = path.startsWith("/") ? path : `/${path}`;
794
+ return `${base}${p}`;
784
795
  }
785
- async function loadOne(level) {
796
+ async loadOne(level) {
797
+ const autoDiscoveryError = this.getAutoDiscoveryError();
786
798
  if (autoDiscoveryError) throw autoDiscoveryError;
787
- assertLevelDeclared(level);
788
- if (cache.get(level)) return;
789
- const existing = inflight.get(level);
799
+ this.assertLevelDeclared(level);
800
+ const noCache = this.state.cacheTtl === null;
801
+ if (!noCache && this.cache.get(level)) return;
802
+ const existing = this.inflight.get(level);
790
803
  if (existing) return existing;
791
- const gen = invalidationGens.get(level) ?? 0;
804
+ const gen = this.invalidationGens.get(level) ?? 0;
792
805
  const p = (async () => {
793
806
  try {
794
- if (level === UNASSIGNED_LEVEL && !backendHasUnassignedLevel && summaryUnassigned) {
795
- const routes = {};
796
- for (const r of summaryUnassigned) {
797
- routes[r.name] = { ...r, level: UNASSIGNED_LEVEL };
798
- }
799
- cache.set({ level: UNASSIGNED_LEVEL, routes, cache: null });
800
- return;
801
- }
802
- const resp = await fetchLevel(level);
803
- if ((invalidationGens.get(level) ?? 0) === gen) {
804
- cache.set(resp);
807
+ const resp = await this.fetchLevel(level);
808
+ if ((this.invalidationGens.get(level) ?? 0) === gen) {
809
+ this.cache.set(resp, this.state.cacheTtl);
805
810
  }
806
811
  } finally {
807
- inflight.delete(level);
812
+ this.inflight.delete(level);
808
813
  }
809
814
  })();
810
- inflight.set(level, p);
815
+ this.inflight.set(level, p);
811
816
  return p;
812
817
  }
813
- async function load(level) {
814
- await autoDiscoveryPromise;
818
+ async load(level) {
819
+ await this.autoDiscoveryPromise;
815
820
  const list = Array.isArray(level) ? level : [level];
816
- await Promise.all(list.map(loadOne));
821
+ await Promise.all(list.map((l) => this.loadOne(l)));
817
822
  }
818
- function route(level, name, params) {
819
- assertDiscoveryReady();
820
- const meta = findRouteMeta(level, name);
821
- if (!meta) {
822
- throw new UnknownRouteError(name, level);
823
- }
824
- return buildRequestUrl(meta, params ?? {});
825
- }
826
- function buildRequestUrl(meta, params) {
827
- const defaults = meta.parameter_defaults ?? {};
828
- const missingRequired = [];
829
- const values = {};
830
- for (const p of meta.parameters) {
831
- let v = params[p];
832
- if ((v === void 0 || v === null) && p in defaults) {
833
- v = defaults[p];
823
+ invalidate(level) {
824
+ if (level === void 0) {
825
+ this.cache.clear();
826
+ this.inflight.clear();
827
+ for (const lvl of this.state.levels) {
828
+ this.invalidationGens.set(lvl, (this.invalidationGens.get(lvl) ?? 0) + 1);
834
829
  }
835
- if (v === void 0 || v === null) {
836
- if (!meta.uri.includes(`{${p}?}`)) {
837
- missingRequired.push(p);
838
- }
839
- } else {
840
- values[p] = v;
830
+ } else if (Array.isArray(level)) {
831
+ for (const lvl of level) {
832
+ this.cache.del(lvl);
833
+ this.inflight.delete(lvl);
834
+ this.invalidationGens.set(lvl, (this.invalidationGens.get(lvl) ?? 0) + 1);
841
835
  }
836
+ } else {
837
+ this.cache.del(level);
838
+ this.inflight.delete(level);
839
+ this.invalidationGens.set(level, (this.invalidationGens.get(level) ?? 0) + 1);
842
840
  }
843
- if (missingRequired.length > 0) {
844
- throw new MissingRouteParamError(meta.name, missingRequired);
845
- }
846
- let uri = meta.uri.replace(/\{([^{}]+)\}/g, (match, raw) => {
847
- const optional = raw.endsWith("?");
848
- const name = optional ? raw.slice(0, -1) : raw;
849
- if (values[name] !== void 0) {
850
- const val = values[name];
851
- if (typeof val === "object") {
852
- throw new ForgeError(
853
- `Path parameter "${name}" must be a primitive value (string, number, boolean), got ${typeof val}`,
854
- { code: "RF_FE_003", route: meta.name, context: { param: name, value: val } }
855
- );
856
- }
857
- return encodeURIComponent(String(val));
858
- }
859
- return optional ? "" : match;
860
- });
861
- uri = uri.replace(/\/+/g, "/").replace(/\/$/, "");
862
- if (/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(effectiveUrlPrefix)) {
863
- const prefix2 = effectiveUrlPrefix.endsWith("/") ? effectiveUrlPrefix.slice(0, -1) : effectiveUrlPrefix;
864
- return uri.startsWith("/") ? `${prefix2}${uri}` : `${prefix2}/${uri}`;
865
- }
866
- const base = baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL;
867
- const prefix = effectiveUrlPrefix;
868
- return uri.startsWith("/") ? `${base}${prefix}${uri}` : `${base}${prefix}/${uri}`;
869
841
  }
870
- function findRouteMeta(level, name) {
871
- const entry = cache.get(level);
842
+ isLoaded(level) {
843
+ if (level) return this.cache.get(level) !== void 0;
844
+ return this.state.levels.length > 0 && this.state.levels.every((lvl) => this.cache.get(lvl) !== void 0);
845
+ }
846
+ findRouteMeta(level, name) {
847
+ const entry = this.cache.get(level);
872
848
  const meta = entry?.routes[name];
873
849
  if (meta) {
874
850
  return { ...meta, level };
875
851
  }
876
852
  return void 0;
877
853
  }
878
- function api(level, name, params = {}) {
879
- let ctrl;
880
- let abortedBeforeInit = false;
881
- let abortReason;
882
- const work = (async () => {
883
- ctrl = new AbortController();
884
- if (abortedBeforeInit) {
885
- ctrl.abort(abortReason);
886
- }
887
- await autoDiscoveryPromise;
888
- await load(level);
889
- const meta = findRouteMeta(level, name);
890
- if (!meta) {
891
- throw new UnknownRouteError(name, level);
854
+ getRoutes(level) {
855
+ if (level !== void 0) {
856
+ const entry = this.cache.get(level);
857
+ const routes = entry?.routes ?? {};
858
+ const result2 = {};
859
+ for (const [k, v] of Object.entries(routes)) {
860
+ result2[k] = JSON.parse(JSON.stringify(v));
892
861
  }
893
- return doApiCall(meta, params, ctrl.signal);
894
- })();
895
- const request = work;
896
- request.abort = () => {
897
- if (ctrl) {
898
- ctrl.abort();
899
- } else {
900
- abortedBeforeInit = true;
862
+ return result2;
863
+ }
864
+ const result = {};
865
+ for (const lvl of this.state.levels) {
866
+ const entry = this.cache.get(lvl);
867
+ if (entry) {
868
+ const levelRoutes = {};
869
+ for (const [k, v] of Object.entries(entry.routes)) {
870
+ levelRoutes[k] = JSON.parse(JSON.stringify(v));
871
+ }
872
+ result[lvl] = levelRoutes;
901
873
  }
902
- };
903
- return request;
874
+ }
875
+ return result;
904
876
  }
877
+ };
878
+
879
+ // src/http-runner.ts
880
+ function createHttpRunner(deps) {
881
+ const {
882
+ ensureAdapter,
883
+ requestInterceptors,
884
+ responseInterceptors,
885
+ load,
886
+ findRouteMeta,
887
+ baseURL,
888
+ state,
889
+ timeout,
890
+ loadingTracker,
891
+ autoDiscoveryPromise
892
+ } = deps;
905
893
  async function doApiCall(meta, params, signal) {
906
894
  const {
907
895
  pathParams,
@@ -914,7 +902,10 @@ function createRouteForge(options) {
914
902
  throw new RequestAbortedError(meta.name, meta.level, signal.reason);
915
903
  }
916
904
  const method = pickMethod(meta);
917
- const urlWithQuery = appendQuery(buildRequestUrl(meta, pathParams), query);
905
+ const urlWithQuery = appendQuery(
906
+ buildRequestUrl(meta, pathParams, { baseURL, urlPrefix: state.urlPrefix }),
907
+ query
908
+ );
918
909
  const config = {
919
910
  route: meta.name,
920
911
  level: meta.level ?? "",
@@ -969,88 +960,77 @@ function createRouteForge(options) {
969
960
  loadingTracker.stop();
970
961
  }
971
962
  }
972
- function invalidate(level) {
973
- if (level === void 0) {
974
- cache.clear();
975
- inflight.clear();
976
- for (const lvl of effectiveLevels) {
977
- invalidationGens.set(lvl, (invalidationGens.get(lvl) ?? 0) + 1);
978
- }
979
- } else if (Array.isArray(level)) {
980
- for (const lvl of level) {
981
- cache.del(lvl);
982
- inflight.delete(lvl);
983
- invalidationGens.set(lvl, (invalidationGens.get(lvl) ?? 0) + 1);
963
+ return function api(level, name, params = {}) {
964
+ let ctrl;
965
+ let abortedBeforeInit = false;
966
+ let abortReason;
967
+ const work = (async () => {
968
+ ctrl = new AbortController();
969
+ if (abortedBeforeInit) {
970
+ ctrl.abort(abortReason);
984
971
  }
985
- } else {
986
- cache.del(level);
987
- inflight.delete(level);
988
- invalidationGens.set(level, (invalidationGens.get(level) ?? 0) + 1);
989
- }
990
- }
991
- function isLoaded(level) {
992
- if (level) return cache.get(level) !== void 0;
993
- return effectiveLevels.length > 0 && effectiveLevels.every((lvl) => cache.get(lvl) !== void 0);
994
- }
995
- function hasRoute(level, name) {
996
- assertDiscoveryReady();
997
- return findRouteMeta(level, name) !== void 0;
998
- }
999
- function getRoutes(level) {
1000
- if (level !== void 0) {
1001
- const entry = cache.get(level);
1002
- const routes = entry?.routes ?? {};
1003
- const result2 = {};
1004
- for (const [k, v] of Object.entries(routes)) {
1005
- result2[k] = JSON.parse(JSON.stringify(v));
972
+ await autoDiscoveryPromise;
973
+ await load(level);
974
+ const meta = findRouteMeta(level, name);
975
+ if (!meta) {
976
+ throw new UnknownRouteError(name, level);
1006
977
  }
1007
- return result2;
1008
- }
1009
- const result = {};
1010
- for (const lvl of effectiveLevels) {
1011
- const entry = cache.get(lvl);
1012
- if (entry) {
1013
- const levelRoutes = {};
1014
- for (const [k, v] of Object.entries(entry.routes)) {
1015
- levelRoutes[k] = JSON.parse(JSON.stringify(v));
1016
- }
1017
- result[lvl] = levelRoutes;
978
+ return doApiCall(meta, params, ctrl.signal);
979
+ })();
980
+ const request = work;
981
+ request.abort = () => {
982
+ if (ctrl) {
983
+ ctrl.abort();
984
+ } else {
985
+ abortedBeforeInit = true;
1018
986
  }
1019
- }
1020
- return result;
1021
- }
1022
- void autoDiscoveryPromise.then(() => {
1023
- autoDiscoveryCompleted = true;
1024
- if (effectiveEager.length > 0) {
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
- });
1034
- });
1035
- }
1036
- }).then(() => {
1037
- resolveReady(forgeInstance);
1038
- }).catch((e) => {
1039
- rejectReady(e);
1040
- });
1041
- function ready(onFulfilled, onRejected) {
1042
- if (onFulfilled) {
1043
- const p = readyPromise.then(onFulfilled, onRejected);
1044
- return p.then(() => forgeInstance);
1045
- }
1046
- return readyPromise;
987
+ };
988
+ return request;
989
+ };
990
+ }
991
+
992
+ // src/resolveRouteName.ts
993
+ async function resolveRouteName(forge, level, prefix, suffix, separator = ".") {
994
+ if (!suffix) return prefix;
995
+ const joined = `${prefix}${separator}${suffix}`;
996
+ if (!suffix.startsWith(`${prefix}${separator}`)) return joined;
997
+ await forge.load(level);
998
+ if (forge.hasRoute(level, joined)) return joined;
999
+ if (forge.hasRoute(level, suffix)) return suffix;
1000
+ throw new UnknownRouteError(joined, level);
1001
+ }
1002
+ function resolveRouteNameSync(forge, level, prefix, suffix, separator = ".") {
1003
+ if (!suffix) return prefix;
1004
+ const joined = `${prefix}${separator}${suffix}`;
1005
+ if (!suffix.startsWith(`${prefix}${separator}`)) return joined;
1006
+ if (forge.hasRoute(level, joined)) return joined;
1007
+ if (forge.hasRoute(level, suffix)) return suffix;
1008
+ throw new UnknownRouteError(joined, level);
1009
+ }
1010
+
1011
+ // src/defineImmutableProps.ts
1012
+ function defineImmutableProps(target, props) {
1013
+ for (const key of Object.keys(props)) {
1014
+ const val = props[key];
1015
+ Object.defineProperty(target, key, {
1016
+ value: val !== null && typeof val === "object" ? Object.freeze(val) : val,
1017
+ writable: false,
1018
+ enumerable: false,
1019
+ configurable: false
1020
+ });
1047
1021
  }
1048
- const forgeResolver = { load, hasRoute };
1022
+ return target;
1023
+ }
1024
+
1025
+ // src/bound-forge.ts
1026
+ function createBoundForgeFactory(deps) {
1027
+ const { load, api, route, hasRoute, getRoutes, invalidate, isLoaded, loadingTracker } = deps;
1028
+ const resolver = { load, hasRoute };
1049
1029
  function createBoundForge(level, prefix) {
1050
1030
  const levelLoadedPromise = load(level);
1051
1031
  levelLoadedPromise.catch(() => {
1052
1032
  });
1053
- const apiFn = prefix ? (name, params) => resolveRouteName(forgeResolver, level, prefix, name).then(
1033
+ const apiFn = prefix ? (name, params) => resolveRouteName(resolver, level, prefix, name).then(
1054
1034
  (resolved) => api(level, resolved, params)
1055
1035
  ) : (name, params) => api(level, name, params);
1056
1036
  const callable = apiFn;
@@ -1058,8 +1038,8 @@ function createRouteForge(options) {
1058
1038
  level,
1059
1039
  ...prefix !== void 0 ? { prefix } : {},
1060
1040
  api: apiFn,
1061
- route: prefix ? (name, params) => route(level, resolveRouteNameSync(forgeResolver, level, prefix, name), params) : (name, params) => route(level, name, params),
1062
- url: prefix ? (name, params) => route(level, resolveRouteNameSync(forgeResolver, level, prefix, name), params) : (name, params) => route(level, name, params),
1041
+ route: prefix ? (name, params) => route(level, resolveRouteNameSync(resolver, level, prefix, name), params) : (name, params) => route(level, name, params),
1042
+ url: prefix ? (name, params) => route(level, resolveRouteNameSync(resolver, level, prefix, name), params) : (name, params) => route(level, name, params),
1063
1043
  hasRoute: (name) => hasRoute(level, name),
1064
1044
  getRoutes: () => getRoutes(level),
1065
1045
  load: () => load(level),
@@ -1103,6 +1083,220 @@ function createRouteForge(options) {
1103
1083
  attachBoundMethods(bound, levelLoadedPromise, level);
1104
1084
  return bound;
1105
1085
  }
1086
+ return createBoundForgeWithMethods;
1087
+ }
1088
+
1089
+ // src/forge.ts
1090
+ var DEFAULT_TIMEOUT = 3e4;
1091
+ var DEFAULT_CACHE_TTL = 3600;
1092
+ function createRouteForge(options) {
1093
+ const bootstrapSummary = readEmbeddedSummary() ?? options.summary ?? null;
1094
+ if (!bootstrapSummary && !options.endpoint) {
1095
+ throw new TypeError(
1096
+ "createRouteForge: \u9700\u8981 options.endpoint\uFF0C\u6216 options.summary\uFF0C\u6216\u9875\u9762\u5185\u5D4C window.__ROUTE_FORGE__"
1097
+ );
1098
+ }
1099
+ const {
1100
+ adapter = "auto",
1101
+ timeout = DEFAULT_TIMEOUT,
1102
+ baseURL = "",
1103
+ interceptors: declarativeInterceptors,
1104
+ cache: cacheOpts = {}
1105
+ } = options;
1106
+ const loadingTracker = new LoadingTracker();
1107
+ const explicitLevels = options.levels;
1108
+ const explicitEager = options.eager;
1109
+ const explicitEndpoint = options.endpoint;
1110
+ const discoveryState = {
1111
+ levels: explicitLevels ?? [],
1112
+ eager: explicitEager ?? [],
1113
+ endpoint: explicitEndpoint ?? bootstrapSummary?.config?.endpoint_prefix ?? "",
1114
+ urlPrefix: "",
1115
+ cacheTtl: void 0,
1116
+ levelRoutes: {}
1117
+ };
1118
+ const discoveryInputs = { explicitLevels, explicitEager, explicitEndpoint };
1119
+ let autoDiscoveryCompleted = false;
1120
+ let resolveReady;
1121
+ let rejectReady;
1122
+ const readyPromise = new Promise((resolve, reject) => {
1123
+ resolveReady = resolve;
1124
+ rejectReady = reject;
1125
+ });
1126
+ readyPromise.catch(() => {
1127
+ });
1128
+ const cacheTtl = cacheOpts.ttl ?? DEFAULT_CACHE_TTL;
1129
+ const cacheStorage = cacheOpts.storage ?? "memory";
1130
+ const cache = new RouteCache({ storage: cacheStorage, ttl: cacheTtl });
1131
+ const requestInterceptors = new InterceptorManagerImpl();
1132
+ const responseInterceptors = new InterceptorManagerImpl();
1133
+ if (declarativeInterceptors?.request) {
1134
+ for (const entry of declarativeInterceptors.request) {
1135
+ if (typeof entry === "function") {
1136
+ requestInterceptors.use(entry);
1137
+ } else {
1138
+ const [onFulfilled, onRejected] = entry;
1139
+ requestInterceptors.use(onFulfilled, onRejected);
1140
+ }
1141
+ }
1142
+ }
1143
+ if (declarativeInterceptors?.response) {
1144
+ for (const entry of declarativeInterceptors.response) {
1145
+ if (typeof entry === "function") {
1146
+ responseInterceptors.use(entry);
1147
+ } else {
1148
+ const [onFulfilled, onRejected] = entry;
1149
+ responseInterceptors.use(onFulfilled, onRejected);
1150
+ }
1151
+ }
1152
+ }
1153
+ const adapterPromise = resolveAdapter({
1154
+ adapter,
1155
+ forgeInterceptors: { request: requestInterceptors, response: responseInterceptors }
1156
+ });
1157
+ let adapterResolved = false;
1158
+ let adapterObj = null;
1159
+ async function ensureAdapter() {
1160
+ if (!adapterResolved) {
1161
+ adapterObj = await adapterPromise.catch((e) => {
1162
+ if (e instanceof AdapterNotFoundError) throw e;
1163
+ return resolveAdapter({
1164
+ adapter: "builtin",
1165
+ forgeInterceptors: { request: requestInterceptors, response: responseInterceptors }
1166
+ });
1167
+ });
1168
+ adapterResolved = true;
1169
+ }
1170
+ return adapterObj;
1171
+ }
1172
+ function assertDiscoveryReady() {
1173
+ if (!autoDiscoveryCompleted && !explicitLevels?.length) {
1174
+ throw new ForgeError(
1175
+ "Route data not available. Auto-discovery has not completed. Use forge.ready() or forge.use(level) first.",
1176
+ { code: "RF_FE_010" }
1177
+ );
1178
+ }
1179
+ }
1180
+ async function fetchMeta(routeTag, url, level = "") {
1181
+ const adp = await ensureAdapter();
1182
+ const config = {
1183
+ route: routeTag,
1184
+ level,
1185
+ method: "GET",
1186
+ url,
1187
+ headers: { Accept: "application/json" },
1188
+ params: {},
1189
+ timeout,
1190
+ meta: {
1191
+ name: routeTag,
1192
+ uri: url,
1193
+ methods: ["GET"],
1194
+ parameters: [],
1195
+ level
1196
+ }
1197
+ };
1198
+ const doRawRequest = adp.requestRaw ?? adp.request;
1199
+ const resp = await doRawRequest(config);
1200
+ if (!resp || resp.status < 200 || resp.status >= 300) {
1201
+ throw new HTTPError(
1202
+ `Failed to fetch "${routeTag}": HTTP ${resp?.status}`,
1203
+ { level, status: resp?.status, url, method: "GET" }
1204
+ );
1205
+ }
1206
+ return resp.data;
1207
+ }
1208
+ let autoDiscoveryPromise;
1209
+ if (bootstrapSummary) {
1210
+ applySummaryToState(bootstrapSummary, discoveryState, discoveryInputs);
1211
+ autoDiscoveryCompleted = true;
1212
+ autoDiscoveryPromise = Promise.resolve();
1213
+ } else {
1214
+ autoDiscoveryPromise = fetchSummary(discoveryInputs, baseURL, fetchMeta).then((summary) => {
1215
+ if (summary === null) {
1216
+ return;
1217
+ }
1218
+ applySummaryToState(summary, discoveryState, discoveryInputs);
1219
+ });
1220
+ }
1221
+ let autoDiscoveryError = null;
1222
+ autoDiscoveryPromise.catch((e) => {
1223
+ autoDiscoveryError = e;
1224
+ });
1225
+ const store = new RouteStore({
1226
+ cache,
1227
+ state: discoveryState,
1228
+ baseURL,
1229
+ fetchMeta,
1230
+ autoDiscoveryPromise,
1231
+ getAutoDiscoveryError: () => autoDiscoveryError
1232
+ });
1233
+ const load = (level) => store.load(level);
1234
+ const findRouteMeta = (level, name) => store.findRouteMeta(level, name);
1235
+ const invalidate = (level) => store.invalidate(level);
1236
+ const isLoaded = (level) => store.isLoaded(level);
1237
+ function getRoutes(level) {
1238
+ return level === void 0 ? store.getRoutes() : store.getRoutes(level);
1239
+ }
1240
+ function route(level, name, params) {
1241
+ assertDiscoveryReady();
1242
+ const meta = findRouteMeta(level, name);
1243
+ if (!meta) {
1244
+ throw new UnknownRouteError(name, level);
1245
+ }
1246
+ return buildRequestUrl(meta, params ?? {}, { baseURL, urlPrefix: discoveryState.urlPrefix });
1247
+ }
1248
+ const api = createHttpRunner({
1249
+ ensureAdapter,
1250
+ requestInterceptors,
1251
+ responseInterceptors,
1252
+ load,
1253
+ findRouteMeta,
1254
+ baseURL,
1255
+ state: discoveryState,
1256
+ timeout,
1257
+ loadingTracker,
1258
+ autoDiscoveryPromise
1259
+ });
1260
+ function hasRoute(level, name) {
1261
+ assertDiscoveryReady();
1262
+ return findRouteMeta(level, name) !== void 0;
1263
+ }
1264
+ void autoDiscoveryPromise.then(() => {
1265
+ autoDiscoveryCompleted = true;
1266
+ if (discoveryState.eager.length > 0) {
1267
+ return Promise.allSettled(discoveryState.eager.map((lvl) => load(lvl))).then((results) => {
1268
+ results.forEach((r, i) => {
1269
+ if (r.status === "rejected") {
1270
+ console.error(
1271
+ `[route-forge] eager load failed for level "${discoveryState.eager[i]}":`,
1272
+ r.reason
1273
+ );
1274
+ }
1275
+ });
1276
+ });
1277
+ }
1278
+ }).then(() => {
1279
+ resolveReady(forgeInstance);
1280
+ }).catch((e) => {
1281
+ rejectReady(e);
1282
+ });
1283
+ function ready(onFulfilled, onRejected) {
1284
+ if (onFulfilled) {
1285
+ const p = readyPromise.then(onFulfilled, onRejected);
1286
+ return p.then(() => forgeInstance);
1287
+ }
1288
+ return readyPromise;
1289
+ }
1290
+ const createBoundForgeWithMethods = createBoundForgeFactory({
1291
+ load,
1292
+ api,
1293
+ route,
1294
+ hasRoute,
1295
+ getRoutes,
1296
+ invalidate,
1297
+ isLoaded,
1298
+ loadingTracker
1299
+ });
1106
1300
  const forgeInstance = {
1107
1301
  api,
1108
1302
  load,
@@ -1126,62 +1320,6 @@ function createRouteForge(options) {
1126
1320
  };
1127
1321
  return forgeInstance;
1128
1322
  }
1129
- function pickMethod(meta) {
1130
- const m = meta.methods.find((x) => x.toUpperCase() !== "HEAD");
1131
- return (m ?? meta.methods[0] ?? "GET").toUpperCase();
1132
- }
1133
- function appendQuery(url, query) {
1134
- if (!query) return url;
1135
- const usp = new URLSearchParams();
1136
- for (const [k, v] of Object.entries(query)) {
1137
- if (v === void 0 || v === null) continue;
1138
- usp.append(k, String(v));
1139
- }
1140
- const qs = usp.toString();
1141
- if (!qs) return url;
1142
- return url.includes("?") ? `${url}&${qs}` : `${url}?${qs}`;
1143
- }
1144
- function resolveApiParams(input) {
1145
- const {
1146
- params: explicitParams,
1147
- query: rawQuery,
1148
- body: rawBody,
1149
- headers: rawHeaders,
1150
- timeout: perCallTimeout,
1151
- ...flatRest
1152
- } = input;
1153
- const pathParams = explicitParams ? { ...explicitParams } : {};
1154
- for (const [k, v] of Object.entries(flatRest)) {
1155
- if (!(k in pathParams)) {
1156
- pathParams[k] = v;
1157
- }
1158
- }
1159
- let query;
1160
- let body;
1161
- let headers;
1162
- if (rawQuery !== void 0) {
1163
- if (typeof rawQuery === "object" && rawQuery !== null) {
1164
- query = rawQuery;
1165
- } else if (!("query" in pathParams)) {
1166
- pathParams.query = rawQuery;
1167
- }
1168
- }
1169
- if (rawBody !== void 0) {
1170
- if (typeof rawBody !== "string" && typeof rawBody !== "number") {
1171
- body = rawBody;
1172
- } else if (!("body" in pathParams)) {
1173
- pathParams.body = rawBody;
1174
- }
1175
- }
1176
- if (rawHeaders !== void 0) {
1177
- if (typeof rawHeaders === "object" && rawHeaders !== null) {
1178
- headers = rawHeaders;
1179
- } else if (!("headers" in pathParams)) {
1180
- pathParams.headers = rawHeaders;
1181
- }
1182
- }
1183
- return { pathParams, query, body, headers, timeout: perCallTimeout };
1184
- }
1185
1323
 
1186
1324
  export { AdapterNotFoundError, ForgeError, HTTPError, InterceptorManagerImpl, InvalidInterceptorReturnError, LoadingTracker, MissingRouteParamError, NetworkError, RequestAbortedError, RouteCache, UnknownLevelError, UnknownRouteError, createInterceptorManager, createRouteForge, resolveRouteName, resolveRouteNameSync };
1187
1325
  //# sourceMappingURL=index.js.map