@route-forge/core 1.2.2 → 1.3.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
@@ -465,6 +465,39 @@ async function resolveAdapter(opts) {
465
465
  return createBuiltinHttp(opts.forgeInterceptors);
466
466
  }
467
467
 
468
+ // src/resolveRouteName.ts
469
+ async function resolveRouteName(forge, level, prefix, suffix, separator = ".") {
470
+ if (!suffix) return prefix;
471
+ const joined = `${prefix}${separator}${suffix}`;
472
+ if (!suffix.startsWith(`${prefix}${separator}`)) return joined;
473
+ await forge.load(level);
474
+ if (forge.hasRoute(level, joined)) return joined;
475
+ if (forge.hasRoute(level, suffix)) return suffix;
476
+ throw new UnknownRouteError(joined, level);
477
+ }
478
+ function resolveRouteNameSync(forge, level, prefix, suffix, separator = ".") {
479
+ if (!suffix) return prefix;
480
+ const joined = `${prefix}${separator}${suffix}`;
481
+ if (!suffix.startsWith(`${prefix}${separator}`)) return joined;
482
+ if (forge.hasRoute(level, joined)) return joined;
483
+ if (forge.hasRoute(level, suffix)) return suffix;
484
+ throw new UnknownRouteError(joined, level);
485
+ }
486
+
487
+ // src/defineImmutableProps.ts
488
+ function defineImmutableProps(target, props) {
489
+ for (const key of Object.keys(props)) {
490
+ const val = props[key];
491
+ Object.defineProperty(target, key, {
492
+ value: val !== null && typeof val === "object" ? Object.freeze(val) : val,
493
+ writable: false,
494
+ enumerable: false,
495
+ configurable: false
496
+ });
497
+ }
498
+ return target;
499
+ }
500
+
468
501
  // src/loading.ts
469
502
  var LoadingTracker = class {
470
503
  constructor() {
@@ -631,7 +664,6 @@ function createRouteForge(options) {
631
664
  const readyPromise = new Promise((resolve) => {
632
665
  resolveReady = resolve;
633
666
  });
634
- const levelLoadedListeners = /* @__PURE__ */ new Map();
635
667
  const cacheTtl = cacheOpts.ttl ?? DEFAULT_CACHE_TTL;
636
668
  const cacheStorage = cacheOpts.storage ?? "memory";
637
669
  const cache = new RouteCache({ storage: cacheStorage, ttl: cacheTtl });
@@ -683,7 +715,7 @@ function createRouteForge(options) {
683
715
  function assertDiscoveryReady() {
684
716
  if (!autoDiscoveryCompleted && !explicitLevels?.length) {
685
717
  throw new ForgeError(
686
- "Route data not available. Auto-discovery has not completed. Use onSummaryReady callback to mount app, or await forge.ready / forge.load(level) first.",
718
+ "Route data not available. Auto-discovery has not completed. Use forge.ready() or forge.use(level) first.",
687
719
  { code: "RF_FE_010" }
688
720
  );
689
721
  }
@@ -736,15 +768,11 @@ function createRouteForge(options) {
736
768
  routes[r.name] = { ...r, level: UNASSIGNED_LEVEL };
737
769
  }
738
770
  cache.set({ level: UNASSIGNED_LEVEL, routes, cache: null });
739
- const listeners = levelLoadedListeners.get(level);
740
- if (listeners) listeners.forEach((cb) => cb());
741
771
  return;
742
772
  }
743
773
  const resp = await fetchLevel(level);
744
774
  if ((invalidationGens.get(level) ?? 0) === gen) {
745
775
  cache.set(resp);
746
- const listeners = levelLoadedListeners.get(level);
747
- if (listeners) listeners.forEach((cb) => cb());
748
776
  }
749
777
  } finally {
750
778
  inflight.delete(level);
@@ -946,6 +974,7 @@ function createRouteForge(options) {
946
974
  return result;
947
975
  }
948
976
  void autoDiscoveryPromise.then(() => {
977
+ autoDiscoveryCompleted = true;
949
978
  options.onSummaryReady?.();
950
979
  if (effectiveEager.length > 0) {
951
980
  return Promise.all(effectiveEager.map((lvl) => load(lvl))).catch((e) => {
@@ -953,11 +982,74 @@ function createRouteForge(options) {
953
982
  });
954
983
  }
955
984
  }).then(() => {
956
- autoDiscoveryCompleted = true;
957
- resolveReady();
985
+ resolveReady(forgeInstance);
958
986
  }).catch(() => {
959
987
  });
960
- return {
988
+ function ready(onFulfilled, onRejected) {
989
+ if (onFulfilled) {
990
+ const p = readyPromise.then(onFulfilled, onRejected);
991
+ return p.then(() => forgeInstance);
992
+ }
993
+ return readyPromise;
994
+ }
995
+ const forgeResolver = { load, hasRoute };
996
+ function createBoundForge(level, prefix) {
997
+ const levelLoadedPromise = load(level).catch(() => {
998
+ });
999
+ const apiFn = prefix ? (name, params) => resolveRouteName(forgeResolver, level, prefix, name).then(
1000
+ (resolved) => api(level, resolved, params)
1001
+ ) : (name, params) => api(level, name, params);
1002
+ const callable = apiFn;
1003
+ defineImmutableProps(callable, {
1004
+ level,
1005
+ ...prefix !== void 0 ? { prefix } : {},
1006
+ api: apiFn,
1007
+ route: prefix ? (name, params) => route(level, resolveRouteNameSync(forgeResolver, level, prefix, name), params) : (name, params) => route(level, name, params),
1008
+ url: prefix ? (name, params) => route(level, resolveRouteNameSync(forgeResolver, level, prefix, name), params) : (name, params) => route(level, name, params),
1009
+ hasRoute: (name) => hasRoute(level, name),
1010
+ getRoutes: () => getRoutes(level),
1011
+ load: () => load(level),
1012
+ invalidate: () => invalidate(level),
1013
+ isLoaded: () => isLoaded(level),
1014
+ isLoading: () => loadingTracker.isLoading(),
1015
+ onLoadingChange: (cb) => loadingTracker.subscribe(cb)
1016
+ });
1017
+ Object.defineProperty(callable, "levelLoaded", {
1018
+ value: levelLoadedPromise,
1019
+ writable: false,
1020
+ enumerable: true,
1021
+ configurable: true
1022
+ });
1023
+ return callable;
1024
+ }
1025
+ function boundOnLevelLoaded(bound, levelLoadedPromise, onFulfilled, onRejected) {
1026
+ const p = levelLoadedPromise.then(() => bound);
1027
+ if (onFulfilled) {
1028
+ return p.then(onFulfilled, onRejected).then(() => bound);
1029
+ }
1030
+ return p;
1031
+ }
1032
+ function attachBoundMethods(bound, levelLoadedPromise, level) {
1033
+ Object.defineProperty(bound, "onLevelLoaded", {
1034
+ value: (onFulfilled, onRejected) => boundOnLevelLoaded(bound, levelLoadedPromise, onFulfilled, onRejected),
1035
+ writable: false,
1036
+ enumerable: false,
1037
+ configurable: false
1038
+ });
1039
+ Object.defineProperty(bound, "useRoutePrefix", {
1040
+ value: (prefix) => createBoundForgeWithMethods(level, prefix),
1041
+ writable: false,
1042
+ enumerable: false,
1043
+ configurable: false
1044
+ });
1045
+ }
1046
+ function createBoundForgeWithMethods(level, prefix) {
1047
+ const bound = createBoundForge(level, prefix);
1048
+ const levelLoadedPromise = bound.levelLoaded;
1049
+ attachBoundMethods(bound, levelLoadedPromise, level);
1050
+ return bound;
1051
+ }
1052
+ const forgeInstance = {
961
1053
  api,
962
1054
  load,
963
1055
  route,
@@ -972,15 +1064,13 @@ function createRouteForge(options) {
972
1064
  request: requestInterceptors,
973
1065
  response: responseInterceptors
974
1066
  },
975
- ready: readyPromise,
976
- onLevelLoaded(level, cb) {
977
- if (!levelLoadedListeners.has(level)) {
978
- levelLoadedListeners.set(level, /* @__PURE__ */ new Set());
979
- }
980
- levelLoadedListeners.get(level).add(cb);
981
- return () => levelLoadedListeners.get(level)?.delete(cb);
1067
+ ready,
1068
+ use(level, prefix) {
1069
+ if (level === void 0) return forgeInstance;
1070
+ return createBoundForgeWithMethods(level, prefix);
982
1071
  }
983
1072
  };
1073
+ return forgeInstance;
984
1074
  }
985
1075
  function pickMethod(meta) {
986
1076
  const m = meta.methods.find((x) => x.toUpperCase() !== "HEAD");
@@ -1048,25 +1138,6 @@ function isAbortError2(err, signal) {
1048
1138
  return false;
1049
1139
  }
1050
1140
 
1051
- // src/resolveRouteName.ts
1052
- async function resolveRouteName(forge, level, prefix, suffix, separator = ".") {
1053
- if (!suffix) return prefix;
1054
- const joined = `${prefix}${separator}${suffix}`;
1055
- if (!suffix.startsWith(`${prefix}${separator}`)) return joined;
1056
- await forge.load(level);
1057
- if (forge.hasRoute(level, joined)) return joined;
1058
- if (forge.hasRoute(level, suffix)) return suffix;
1059
- throw new UnknownRouteError(joined, level);
1060
- }
1061
- function resolveRouteNameSync(forge, level, prefix, suffix, separator = ".") {
1062
- if (!suffix) return prefix;
1063
- const joined = `${prefix}${separator}${suffix}`;
1064
- if (!suffix.startsWith(`${prefix}${separator}`)) return joined;
1065
- if (forge.hasRoute(level, joined)) return joined;
1066
- if (forge.hasRoute(level, suffix)) return suffix;
1067
- throw new UnknownRouteError(joined, level);
1068
- }
1069
-
1070
1141
  export { AdapterNotFoundError, ForgeError, HTTPError, InterceptorManagerImpl, InvalidInterceptorReturnError, LoadingTracker, MissingRouteParamError, NetworkError, RequestAbortedError, RouteCache, UnknownLevelError, UnknownRouteError, createInterceptorManager, createRouteForge, resolveRouteName, resolveRouteNameSync };
1071
1142
  //# sourceMappingURL=index.js.map
1072
1143
  //# sourceMappingURL=index.js.map