@route-forge/core 1.1.0 → 1.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/README.md +55 -3
- package/dist/codegen.d.cts +1 -1
- package/dist/codegen.d.ts +1 -1
- package/dist/defineImmutableProps.cjs +19 -0
- package/dist/defineImmutableProps.cjs.map +1 -0
- package/dist/defineImmutableProps.d.cts +10 -0
- package/dist/defineImmutableProps.d.ts +10 -0
- package/dist/defineImmutableProps.js +17 -0
- package/dist/defineImmutableProps.js.map +1 -0
- package/dist/index.cjs +87 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -3
- package/dist/index.d.ts +34 -3
- package/dist/index.js +86 -10
- package/dist/index.js.map +1 -1
- package/dist/route-forge.global.js +1094 -0
- package/dist/route-forge.global.js.map +1 -0
- package/dist/route-forge.global.min.js +2 -0
- package/dist/{types-pHQLqpYF.d.cts → types-CMouq7zD.d.cts} +104 -1
- package/dist/{types-pHQLqpYF.d.ts → types-CMouq7zD.d.ts} +104 -1
- package/package.json +13 -4
package/dist/index.js
CHANGED
|
@@ -387,10 +387,11 @@ function toHeaders(raw) {
|
|
|
387
387
|
}
|
|
388
388
|
async function wrapAxiosAdapter() {
|
|
389
389
|
let axios;
|
|
390
|
+
const axiosModule = "axios";
|
|
390
391
|
try {
|
|
391
392
|
const mod = await import(
|
|
392
393
|
/* @vite-ignore */
|
|
393
|
-
|
|
394
|
+
axiosModule
|
|
394
395
|
);
|
|
395
396
|
axios = mod.default ?? mod;
|
|
396
397
|
} catch {
|
|
@@ -621,8 +622,16 @@ function createRouteForge(options) {
|
|
|
621
622
|
effectiveEager = [...union];
|
|
622
623
|
}
|
|
623
624
|
});
|
|
624
|
-
|
|
625
|
+
let autoDiscoveryError = null;
|
|
626
|
+
autoDiscoveryPromise.catch((e) => {
|
|
627
|
+
autoDiscoveryError = e;
|
|
625
628
|
});
|
|
629
|
+
let autoDiscoveryCompleted = false;
|
|
630
|
+
let resolveReady;
|
|
631
|
+
const readyPromise = new Promise((resolve) => {
|
|
632
|
+
resolveReady = resolve;
|
|
633
|
+
});
|
|
634
|
+
const levelLoadedListeners = /* @__PURE__ */ new Map();
|
|
626
635
|
const cacheTtl = cacheOpts.ttl ?? DEFAULT_CACHE_TTL;
|
|
627
636
|
const cacheStorage = cacheOpts.storage ?? "memory";
|
|
628
637
|
const cache = new RouteCache({ storage: cacheStorage, ttl: cacheTtl });
|
|
@@ -665,11 +674,20 @@ function createRouteForge(options) {
|
|
|
665
674
|
return adapterObj;
|
|
666
675
|
}
|
|
667
676
|
const inflight = /* @__PURE__ */ new Map();
|
|
677
|
+
const invalidationGens = /* @__PURE__ */ new Map();
|
|
668
678
|
function assertLevelDeclared(level) {
|
|
669
679
|
if (!effectiveLevels.includes(level)) {
|
|
670
680
|
throw new UnknownLevelError(level);
|
|
671
681
|
}
|
|
672
682
|
}
|
|
683
|
+
function assertDiscoveryReady() {
|
|
684
|
+
if (!autoDiscoveryCompleted && !explicitLevels?.length) {
|
|
685
|
+
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.",
|
|
687
|
+
{ code: "RF_FE_010" }
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
673
691
|
function buildUrl(level) {
|
|
674
692
|
const base = baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL;
|
|
675
693
|
const ep = effectiveEndpoint.startsWith("/") ? effectiveEndpoint : `/${effectiveEndpoint}`;
|
|
@@ -704,10 +722,12 @@ function createRouteForge(options) {
|
|
|
704
722
|
return data;
|
|
705
723
|
}
|
|
706
724
|
async function loadOne(level) {
|
|
725
|
+
if (autoDiscoveryError) throw autoDiscoveryError;
|
|
707
726
|
assertLevelDeclared(level);
|
|
708
727
|
if (cache.get(level)) return;
|
|
709
728
|
const existing = inflight.get(level);
|
|
710
729
|
if (existing) return existing;
|
|
730
|
+
const gen = invalidationGens.get(level) ?? 0;
|
|
711
731
|
const p = (async () => {
|
|
712
732
|
try {
|
|
713
733
|
if (level === UNASSIGNED_LEVEL && !backendHasUnassignedLevel && summaryUnassigned) {
|
|
@@ -716,10 +736,16 @@ function createRouteForge(options) {
|
|
|
716
736
|
routes[r.name] = { ...r, level: UNASSIGNED_LEVEL };
|
|
717
737
|
}
|
|
718
738
|
cache.set({ level: UNASSIGNED_LEVEL, routes, cache: null });
|
|
739
|
+
const listeners = levelLoadedListeners.get(level);
|
|
740
|
+
if (listeners) listeners.forEach((cb) => cb());
|
|
719
741
|
return;
|
|
720
742
|
}
|
|
721
743
|
const resp = await fetchLevel(level);
|
|
722
|
-
|
|
744
|
+
if ((invalidationGens.get(level) ?? 0) === gen) {
|
|
745
|
+
cache.set(resp);
|
|
746
|
+
const listeners = levelLoadedListeners.get(level);
|
|
747
|
+
if (listeners) listeners.forEach((cb) => cb());
|
|
748
|
+
}
|
|
723
749
|
} finally {
|
|
724
750
|
inflight.delete(level);
|
|
725
751
|
}
|
|
@@ -733,6 +759,7 @@ function createRouteForge(options) {
|
|
|
733
759
|
await Promise.all(list.map(loadOne));
|
|
734
760
|
}
|
|
735
761
|
function route(level, name, params) {
|
|
762
|
+
assertDiscoveryReady();
|
|
736
763
|
const meta = findRouteMeta(level, name);
|
|
737
764
|
if (!meta) {
|
|
738
765
|
throw new UnknownRouteError(name, level);
|
|
@@ -763,12 +790,19 @@ function createRouteForge(options) {
|
|
|
763
790
|
const optional = raw.endsWith("?");
|
|
764
791
|
const name = optional ? raw.slice(0, -1) : raw;
|
|
765
792
|
if (values[name] !== void 0) {
|
|
766
|
-
|
|
793
|
+
const val = values[name];
|
|
794
|
+
if (typeof val === "object") {
|
|
795
|
+
throw new ForgeError(
|
|
796
|
+
`Path parameter "${name}" must be a primitive value (string, number, boolean), got ${typeof val}`,
|
|
797
|
+
{ code: "RF_FE_003", route: meta.name, context: { param: name, value: val } }
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
return encodeURIComponent(String(val));
|
|
767
801
|
}
|
|
768
802
|
return optional ? "" : match;
|
|
769
803
|
});
|
|
770
804
|
uri = uri.replace(/\/+/g, "/").replace(/\/$/, "");
|
|
771
|
-
if (effectiveUrlPrefix
|
|
805
|
+
if (/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(effectiveUrlPrefix)) {
|
|
772
806
|
const prefix2 = effectiveUrlPrefix.endsWith("/") ? effectiveUrlPrefix.slice(0, -1) : effectiveUrlPrefix;
|
|
773
807
|
return uri.startsWith("/") ? `${prefix2}${uri}` : `${prefix2}/${uri}`;
|
|
774
808
|
}
|
|
@@ -864,10 +898,20 @@ function createRouteForge(options) {
|
|
|
864
898
|
function invalidate(level) {
|
|
865
899
|
if (level === void 0) {
|
|
866
900
|
cache.clear();
|
|
901
|
+
inflight.clear();
|
|
902
|
+
for (const lvl of effectiveLevels) {
|
|
903
|
+
invalidationGens.set(lvl, (invalidationGens.get(lvl) ?? 0) + 1);
|
|
904
|
+
}
|
|
867
905
|
} else if (Array.isArray(level)) {
|
|
868
|
-
for (const lvl of level)
|
|
906
|
+
for (const lvl of level) {
|
|
907
|
+
cache.del(lvl);
|
|
908
|
+
inflight.delete(lvl);
|
|
909
|
+
invalidationGens.set(lvl, (invalidationGens.get(lvl) ?? 0) + 1);
|
|
910
|
+
}
|
|
869
911
|
} else {
|
|
870
912
|
cache.del(level);
|
|
913
|
+
inflight.delete(level);
|
|
914
|
+
invalidationGens.set(level, (invalidationGens.get(level) ?? 0) + 1);
|
|
871
915
|
}
|
|
872
916
|
}
|
|
873
917
|
function isLoaded(level) {
|
|
@@ -875,6 +919,7 @@ function createRouteForge(options) {
|
|
|
875
919
|
return effectiveLevels.length > 0 && effectiveLevels.every((lvl) => cache.get(lvl) !== void 0);
|
|
876
920
|
}
|
|
877
921
|
function hasRoute(level, name) {
|
|
922
|
+
assertDiscoveryReady();
|
|
878
923
|
return findRouteMeta(level, name) !== void 0;
|
|
879
924
|
}
|
|
880
925
|
function getRoutes(level) {
|
|
@@ -883,7 +928,7 @@ function createRouteForge(options) {
|
|
|
883
928
|
const routes = entry?.routes ?? {};
|
|
884
929
|
const result2 = {};
|
|
885
930
|
for (const [k, v] of Object.entries(routes)) {
|
|
886
|
-
result2[k] =
|
|
931
|
+
result2[k] = JSON.parse(JSON.stringify(v));
|
|
887
932
|
}
|
|
888
933
|
return result2;
|
|
889
934
|
}
|
|
@@ -893,7 +938,7 @@ function createRouteForge(options) {
|
|
|
893
938
|
if (entry) {
|
|
894
939
|
const levelRoutes = {};
|
|
895
940
|
for (const [k, v] of Object.entries(entry.routes)) {
|
|
896
|
-
levelRoutes[k] =
|
|
941
|
+
levelRoutes[k] = JSON.parse(JSON.stringify(v));
|
|
897
942
|
}
|
|
898
943
|
result[lvl] = levelRoutes;
|
|
899
944
|
}
|
|
@@ -901,11 +946,15 @@ function createRouteForge(options) {
|
|
|
901
946
|
return result;
|
|
902
947
|
}
|
|
903
948
|
void autoDiscoveryPromise.then(() => {
|
|
949
|
+
options.onSummaryReady?.();
|
|
904
950
|
if (effectiveEager.length > 0) {
|
|
905
|
-
|
|
951
|
+
return Promise.all(effectiveEager.map((lvl) => load(lvl))).catch((e) => {
|
|
906
952
|
console.warn(`[route-forge] eager load failed: ${e.message}`);
|
|
907
953
|
});
|
|
908
954
|
}
|
|
955
|
+
}).then(() => {
|
|
956
|
+
autoDiscoveryCompleted = true;
|
|
957
|
+
resolveReady();
|
|
909
958
|
}).catch(() => {
|
|
910
959
|
});
|
|
911
960
|
return {
|
|
@@ -922,6 +971,14 @@ function createRouteForge(options) {
|
|
|
922
971
|
interceptors: {
|
|
923
972
|
request: requestInterceptors,
|
|
924
973
|
response: responseInterceptors
|
|
974
|
+
},
|
|
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);
|
|
925
982
|
}
|
|
926
983
|
};
|
|
927
984
|
}
|
|
@@ -991,6 +1048,25 @@ function isAbortError2(err, signal) {
|
|
|
991
1048
|
return false;
|
|
992
1049
|
}
|
|
993
1050
|
|
|
994
|
-
|
|
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
|
+
export { AdapterNotFoundError, ForgeError, HTTPError, InterceptorManagerImpl, InvalidInterceptorReturnError, LoadingTracker, MissingRouteParamError, NetworkError, RequestAbortedError, RouteCache, UnknownLevelError, UnknownRouteError, createInterceptorManager, createRouteForge, resolveRouteName, resolveRouteNameSync };
|
|
995
1071
|
//# sourceMappingURL=index.js.map
|
|
996
1072
|
//# sourceMappingURL=index.js.map
|