@route-forge/core 2.2.0 → 3.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 +32 -24
- package/README_zh.md +31 -24
- package/dist/codegen.cjs +7 -8
- package/dist/codegen.cjs.map +1 -1
- package/dist/codegen.d.cts +2 -3
- package/dist/codegen.d.ts +2 -3
- package/dist/codegen.js +7 -8
- package/dist/codegen.js.map +1 -1
- package/dist/index.cjs +183 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -9
- package/dist/index.d.ts +28 -9
- package/dist/index.js +182 -84
- package/dist/index.js.map +1 -1
- package/dist/route-forge.global.js +183 -83
- package/dist/route-forge.global.js.map +1 -1
- package/dist/route-forge.global.min.js +2 -2
- package/dist/{types-CDKE8rw-.d.cts → types-B_vdcRqx.d.cts} +57 -18
- package/dist/{types-CDKE8rw-.d.ts → types-B_vdcRqx.d.ts} +57 -18
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -141,30 +141,56 @@ var ForgeError = class extends Error {
|
|
|
141
141
|
if (opts.cause !== void 0) this.cause = opts.cause;
|
|
142
142
|
}
|
|
143
143
|
};
|
|
144
|
+
function formatCandidates(candidates) {
|
|
145
|
+
if (!candidates || candidates.length === 0) return "";
|
|
146
|
+
const MAX = 5;
|
|
147
|
+
const shown = candidates.slice(0, MAX).join(", ");
|
|
148
|
+
const more = candidates.length > MAX ? ` (+${candidates.length - MAX} more)` : "";
|
|
149
|
+
return ` Available: ${shown}${more}`;
|
|
150
|
+
}
|
|
144
151
|
var UnknownRouteError = class extends ForgeError {
|
|
145
|
-
constructor(route, level) {
|
|
146
|
-
super(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
152
|
+
constructor(route, level, candidates) {
|
|
153
|
+
super(
|
|
154
|
+
`Route "${route}" not found${level ? ` in level "${level}"` : ""}.${formatCandidates(candidates)}`,
|
|
155
|
+
{
|
|
156
|
+
code: "RF_FE_001",
|
|
157
|
+
route,
|
|
158
|
+
level,
|
|
159
|
+
context: candidates && candidates.length > 0 ? { candidates } : void 0
|
|
160
|
+
}
|
|
161
|
+
);
|
|
151
162
|
}
|
|
152
163
|
};
|
|
153
164
|
var UnknownLevelError = class extends ForgeError {
|
|
154
|
-
constructor(level) {
|
|
155
|
-
super(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
165
|
+
constructor(level, candidates) {
|
|
166
|
+
super(
|
|
167
|
+
`Level "${level}" not declared in options.levels.${formatCandidates(candidates)}`,
|
|
168
|
+
{
|
|
169
|
+
code: "RF_FE_002",
|
|
170
|
+
level,
|
|
171
|
+
context: candidates && candidates.length > 0 ? { candidates } : void 0
|
|
172
|
+
}
|
|
173
|
+
);
|
|
159
174
|
}
|
|
160
175
|
};
|
|
161
176
|
var MissingRouteParamError = class extends ForgeError {
|
|
162
|
-
constructor(route, missingParams) {
|
|
163
|
-
super(
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
177
|
+
constructor(route, missingParams, uri) {
|
|
178
|
+
super(
|
|
179
|
+
`Missing path parameter(s) ${missingParams.join(", ")} for route "${route}"${uri ? ` (${uri})` : ""}`,
|
|
180
|
+
{
|
|
181
|
+
code: "RF_FE_003",
|
|
182
|
+
route,
|
|
183
|
+
context: { missingParams, ...uri !== void 0 ? { uri } : {} }
|
|
184
|
+
}
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
var InvalidPathParamError = class extends ForgeError {
|
|
189
|
+
constructor(route, param, value) {
|
|
190
|
+
super(
|
|
191
|
+
`Path parameter "${param}" must be a primitive value (string, number, boolean), got ${typeof value}`,
|
|
192
|
+
{ code: "RF_FE_003", route, context: { param, value } }
|
|
193
|
+
);
|
|
168
194
|
}
|
|
169
195
|
};
|
|
170
196
|
var AdapterNotFoundError = class extends ForgeError {
|
|
@@ -197,6 +223,7 @@ var HTTPError = class extends ForgeError {
|
|
|
197
223
|
context: { status: opts.status, url: opts.url, method: opts.method },
|
|
198
224
|
cause: opts.cause
|
|
199
225
|
});
|
|
226
|
+
if (opts.response !== void 0) this.response = opts.response;
|
|
200
227
|
}
|
|
201
228
|
};
|
|
202
229
|
var RequestAbortedError = class extends ForgeError {
|
|
@@ -209,6 +236,14 @@ var RequestAbortedError = class extends ForgeError {
|
|
|
209
236
|
});
|
|
210
237
|
}
|
|
211
238
|
};
|
|
239
|
+
var DiscoveryNotReadyError = class extends ForgeError {
|
|
240
|
+
constructor() {
|
|
241
|
+
super(
|
|
242
|
+
"Route data not available. Auto-discovery has not completed. Use forge.ready() or forge.use(level) first, or await ready() before calling route()/hasRoute().",
|
|
243
|
+
{ code: "RF_FE_010" }
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
};
|
|
212
247
|
|
|
213
248
|
// src/interceptors.ts
|
|
214
249
|
var InterceptorManagerImpl = class {
|
|
@@ -275,6 +310,43 @@ async function runResponseInterceptors(manager, source) {
|
|
|
275
310
|
function createInterceptorManager() {
|
|
276
311
|
return new InterceptorManagerImpl();
|
|
277
312
|
}
|
|
313
|
+
function normalizeInterceptorDeclaration(value) {
|
|
314
|
+
if (value === null || value === void 0) return {};
|
|
315
|
+
let rawResolve;
|
|
316
|
+
let rawReject;
|
|
317
|
+
if (typeof value === "function") {
|
|
318
|
+
rawResolve = value;
|
|
319
|
+
} else if (Array.isArray(value)) {
|
|
320
|
+
rawResolve = value[0];
|
|
321
|
+
rawReject = value[1];
|
|
322
|
+
} else if (typeof value === "object") {
|
|
323
|
+
const obj = value;
|
|
324
|
+
rawResolve = obj.resolve;
|
|
325
|
+
rawReject = obj.reject;
|
|
326
|
+
} else {
|
|
327
|
+
throw new TypeError(
|
|
328
|
+
`Interceptor declaration must be a function, a [resolve, reject] tuple, or a { resolve, reject } object; received ${typeof value}.`
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
const handler = {};
|
|
332
|
+
if (rawResolve !== void 0 && rawResolve !== null) {
|
|
333
|
+
if (typeof rawResolve !== "function") {
|
|
334
|
+
throw new TypeError(
|
|
335
|
+
`Interceptor "resolve" (onFulfilled) must be a function; received ${typeof rawResolve}.`
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
handler.onFulfilled = rawResolve;
|
|
339
|
+
}
|
|
340
|
+
if (rawReject !== void 0 && rawReject !== null) {
|
|
341
|
+
if (typeof rawReject !== "function") {
|
|
342
|
+
throw new TypeError(
|
|
343
|
+
`Interceptor "reject" (onRejected) must be a function; received ${typeof rawReject}.`
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
handler.onRejected = rawReject;
|
|
347
|
+
}
|
|
348
|
+
return handler;
|
|
349
|
+
}
|
|
278
350
|
|
|
279
351
|
// src/adapters/fetch-core.ts
|
|
280
352
|
function isAbortError(err, signal) {
|
|
@@ -375,7 +447,10 @@ async function rawFetch(config) {
|
|
|
375
447
|
level: config.level,
|
|
376
448
|
status: res.status,
|
|
377
449
|
url,
|
|
378
|
-
method: config.method
|
|
450
|
+
method: config.method,
|
|
451
|
+
// 完整 ResponseData 随错误逐段传递(响应拦截器 onRejected 链 → 最终 catch),
|
|
452
|
+
// 供调用方检查响应体,如 Laravel 422 校验错误 err.response.data.errors
|
|
453
|
+
response: responseData
|
|
379
454
|
}
|
|
380
455
|
);
|
|
381
456
|
}
|
|
@@ -587,7 +662,7 @@ function buildRequestUrl(meta, params, ctx) {
|
|
|
587
662
|
}
|
|
588
663
|
}
|
|
589
664
|
if (missingRequired.length > 0) {
|
|
590
|
-
throw new MissingRouteParamError(meta.name, missingRequired);
|
|
665
|
+
throw new MissingRouteParamError(meta.name, missingRequired, meta.uri);
|
|
591
666
|
}
|
|
592
667
|
let uri = meta.uri.replace(/\{([^{}]+)\}/g, (match, raw) => {
|
|
593
668
|
const optional = raw.endsWith("?");
|
|
@@ -595,10 +670,7 @@ function buildRequestUrl(meta, params, ctx) {
|
|
|
595
670
|
if (values[name] !== void 0) {
|
|
596
671
|
const val = values[name];
|
|
597
672
|
if (typeof val === "object") {
|
|
598
|
-
throw new
|
|
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
|
-
);
|
|
673
|
+
throw new InvalidPathParamError(meta.name, name, val);
|
|
602
674
|
}
|
|
603
675
|
return encodeURIComponent(String(val));
|
|
604
676
|
}
|
|
@@ -671,24 +743,31 @@ function resolveApiParams(input) {
|
|
|
671
743
|
}
|
|
672
744
|
|
|
673
745
|
// src/auto-discovery.ts
|
|
746
|
+
var DEFAULT_ENDPOINT = "/_forge/routes";
|
|
674
747
|
async function fetchSummary(inputs, baseURL, fetchMeta) {
|
|
675
|
-
const { explicitLevels, explicitEndpoint } = inputs;
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
}
|
|
748
|
+
const { explicitLevels, explicitEndpoint, warnings } = inputs;
|
|
749
|
+
const endpoint = explicitEndpoint ?? DEFAULT_ENDPOINT;
|
|
750
|
+
const base = baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL;
|
|
751
|
+
const ep = endpoint.startsWith("/") ? endpoint : `/${endpoint}`;
|
|
752
|
+
const url = `${base}${ep}`;
|
|
679
753
|
try {
|
|
680
|
-
const
|
|
681
|
-
const ep = explicitEndpoint.startsWith("/") ? explicitEndpoint : `/${explicitEndpoint}`;
|
|
682
|
-
const data = await fetchMeta("__forge__.summary", `${base}${ep}`);
|
|
754
|
+
const data = await fetchMeta("__forge__.summary", url);
|
|
683
755
|
return data;
|
|
684
756
|
} catch (e) {
|
|
685
757
|
if (explicitLevels && explicitLevels.length > 0) {
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
758
|
+
if (warnings) {
|
|
759
|
+
console.warn(
|
|
760
|
+
`[route-forge] summary endpoint unreachable: ${e.message}; using explicit levels`
|
|
761
|
+
);
|
|
762
|
+
}
|
|
689
763
|
return null;
|
|
690
764
|
}
|
|
691
|
-
throw new
|
|
765
|
+
throw new NetworkError(
|
|
766
|
+
`Failed to fetch route summary from "${url}": ${e?.message ?? String(e)}; check the backend manifest endpoint or options.endpoint`,
|
|
767
|
+
void 0,
|
|
768
|
+
void 0,
|
|
769
|
+
e
|
|
770
|
+
);
|
|
692
771
|
}
|
|
693
772
|
}
|
|
694
773
|
function normalizeCacheTtl(raw) {
|
|
@@ -696,15 +775,15 @@ function normalizeCacheTtl(raw) {
|
|
|
696
775
|
return raw;
|
|
697
776
|
}
|
|
698
777
|
function applySummaryToState(summary, state, inputs) {
|
|
699
|
-
const { explicitLevels, explicitEager, explicitEndpoint } = inputs;
|
|
778
|
+
const { explicitLevels, explicitEager, explicitEndpoint, warnings } = inputs;
|
|
700
779
|
const schemeVersion = summary.schemeVersion ?? 1;
|
|
701
|
-
if (schemeVersion > 1) {
|
|
780
|
+
if (schemeVersion > 1 && warnings) {
|
|
702
781
|
console.warn(
|
|
703
782
|
`[route-forge] backend schemeVersion=${schemeVersion} > client supported 1; some features may be unavailable`
|
|
704
783
|
);
|
|
705
784
|
}
|
|
706
785
|
if (summary.config.endpoint_prefix && summary.config.endpoint_prefix !== explicitEndpoint) {
|
|
707
|
-
if (explicitEndpoint) {
|
|
786
|
+
if (explicitEndpoint && warnings) {
|
|
708
787
|
console.warn(
|
|
709
788
|
`[route-forge] backend endpoint_prefix "${summary.config.endpoint_prefix}" overrides frontend endpoint "${explicitEndpoint}"`
|
|
710
789
|
);
|
|
@@ -727,7 +806,7 @@ function applySummaryToState(summary, state, inputs) {
|
|
|
727
806
|
if (explicitLevels && explicitLevels.length > 0) {
|
|
728
807
|
const intersection = explicitLevels.filter((l) => backendLevels.includes(l));
|
|
729
808
|
const removed = explicitLevels.filter((l) => !backendLevels.includes(l));
|
|
730
|
-
if (removed.length > 0) {
|
|
809
|
+
if (removed.length > 0 && warnings) {
|
|
731
810
|
console.warn(
|
|
732
811
|
`[route-forge] levels not in backend summary and dropped: ${removed.join(", ")}`
|
|
733
812
|
);
|
|
@@ -779,7 +858,7 @@ var RouteStore = class {
|
|
|
779
858
|
}
|
|
780
859
|
assertLevelDeclared(level) {
|
|
781
860
|
if (!this.state.levels.includes(level)) {
|
|
782
|
-
throw new UnknownLevelError(level);
|
|
861
|
+
throw new UnknownLevelError(level, this.state.levels);
|
|
783
862
|
}
|
|
784
863
|
}
|
|
785
864
|
async fetchLevel(level) {
|
|
@@ -853,6 +932,7 @@ var RouteStore = class {
|
|
|
853
932
|
}
|
|
854
933
|
getRoutes(level) {
|
|
855
934
|
if (level !== void 0) {
|
|
935
|
+
this.assertLevelDeclared(level);
|
|
856
936
|
const entry = this.cache.get(level);
|
|
857
937
|
const routes = entry?.routes ?? {};
|
|
858
938
|
const result2 = {};
|
|
@@ -884,6 +964,7 @@ function createHttpRunner(deps) {
|
|
|
884
964
|
responseInterceptors,
|
|
885
965
|
load,
|
|
886
966
|
findRouteMeta,
|
|
967
|
+
getRouteNames,
|
|
887
968
|
baseURL,
|
|
888
969
|
state,
|
|
889
970
|
timeout,
|
|
@@ -935,7 +1016,10 @@ function createHttpRunner(deps) {
|
|
|
935
1016
|
level: resp.level,
|
|
936
1017
|
status: resp.status,
|
|
937
1018
|
url: resp.url,
|
|
938
|
-
method: resp.method
|
|
1019
|
+
method: resp.method,
|
|
1020
|
+
// 完整 ResponseData 随错误逐段传递(响应拦截器 onRejected 链 → 最终 catch),
|
|
1021
|
+
// 供调用方检查响应体,如 Laravel 422 校验错误 err.response.data.errors
|
|
1022
|
+
response: resp
|
|
939
1023
|
}
|
|
940
1024
|
);
|
|
941
1025
|
}
|
|
@@ -973,7 +1057,7 @@ function createHttpRunner(deps) {
|
|
|
973
1057
|
await load(level);
|
|
974
1058
|
const meta = findRouteMeta(level, name);
|
|
975
1059
|
if (!meta) {
|
|
976
|
-
throw new UnknownRouteError(name, level);
|
|
1060
|
+
throw new UnknownRouteError(name, level, getRouteNames(level));
|
|
977
1061
|
}
|
|
978
1062
|
return doApiCall(meta, params, ctrl.signal);
|
|
979
1063
|
})();
|
|
@@ -990,22 +1074,31 @@ function createHttpRunner(deps) {
|
|
|
990
1074
|
}
|
|
991
1075
|
|
|
992
1076
|
// src/resolveRouteName.ts
|
|
1077
|
+
function stripTrailingSeparator(prefix, separator) {
|
|
1078
|
+
let normalized = prefix;
|
|
1079
|
+
while (normalized.endsWith(separator)) {
|
|
1080
|
+
normalized = normalized.slice(0, -separator.length);
|
|
1081
|
+
}
|
|
1082
|
+
return normalized;
|
|
1083
|
+
}
|
|
993
1084
|
async function resolveRouteName(forge, level, prefix, suffix, separator = ".") {
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1085
|
+
const normalized = stripTrailingSeparator(prefix, separator);
|
|
1086
|
+
if (!suffix) return normalized;
|
|
1087
|
+
const joined = `${normalized}${separator}${suffix}`;
|
|
1088
|
+
if (!suffix.startsWith(`${normalized}${separator}`)) return joined;
|
|
997
1089
|
await forge.load(level);
|
|
998
1090
|
if (forge.hasRoute(level, joined)) return joined;
|
|
999
1091
|
if (forge.hasRoute(level, suffix)) return suffix;
|
|
1000
|
-
throw new UnknownRouteError(joined, level);
|
|
1092
|
+
throw new UnknownRouteError(joined, level, forge.getRouteNames?.(level));
|
|
1001
1093
|
}
|
|
1002
1094
|
function resolveRouteNameSync(forge, level, prefix, suffix, separator = ".") {
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1095
|
+
const normalized = stripTrailingSeparator(prefix, separator);
|
|
1096
|
+
if (!suffix) return normalized;
|
|
1097
|
+
const joined = `${normalized}${separator}${suffix}`;
|
|
1098
|
+
if (!suffix.startsWith(`${normalized}${separator}`)) return joined;
|
|
1006
1099
|
if (forge.hasRoute(level, joined)) return joined;
|
|
1007
1100
|
if (forge.hasRoute(level, suffix)) return suffix;
|
|
1008
|
-
throw new UnknownRouteError(joined, level);
|
|
1101
|
+
throw new UnknownRouteError(joined, level, forge.getRouteNames?.(level));
|
|
1009
1102
|
}
|
|
1010
1103
|
|
|
1011
1104
|
// src/defineImmutableProps.ts
|
|
@@ -1025,7 +1118,7 @@ function defineImmutableProps(target, props) {
|
|
|
1025
1118
|
// src/bound-forge.ts
|
|
1026
1119
|
function createBoundForgeFactory(deps) {
|
|
1027
1120
|
const { load, api, route, hasRoute, getRoutes, invalidate, isLoaded, loadingTracker } = deps;
|
|
1028
|
-
const resolver = { load, hasRoute };
|
|
1121
|
+
const resolver = { load, hasRoute, getRouteNames: (lvl) => Object.keys(getRoutes(lvl)) };
|
|
1029
1122
|
function createBoundForge(level, prefix) {
|
|
1030
1123
|
const levelLoadedPromise = load(level);
|
|
1031
1124
|
levelLoadedPromise.catch(() => {
|
|
@@ -1089,13 +1182,8 @@ function createBoundForgeFactory(deps) {
|
|
|
1089
1182
|
// src/forge.ts
|
|
1090
1183
|
var DEFAULT_TIMEOUT = 3e4;
|
|
1091
1184
|
var DEFAULT_CACHE_TTL = 3600;
|
|
1092
|
-
function createRouteForge(options) {
|
|
1185
|
+
function createRouteForge(options = {}) {
|
|
1093
1186
|
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
1187
|
const {
|
|
1100
1188
|
adapter = "auto",
|
|
1101
1189
|
timeout = DEFAULT_TIMEOUT,
|
|
@@ -1103,6 +1191,7 @@ function createRouteForge(options) {
|
|
|
1103
1191
|
interceptors: declarativeInterceptors,
|
|
1104
1192
|
cache: cacheOpts = {}
|
|
1105
1193
|
} = options;
|
|
1194
|
+
const warnings = options.warnings ?? true;
|
|
1106
1195
|
const loadingTracker = new LoadingTracker();
|
|
1107
1196
|
const explicitLevels = options.levels;
|
|
1108
1197
|
const explicitEager = options.eager;
|
|
@@ -1110,12 +1199,12 @@ function createRouteForge(options) {
|
|
|
1110
1199
|
const discoveryState = {
|
|
1111
1200
|
levels: explicitLevels ?? [],
|
|
1112
1201
|
eager: explicitEager ?? [],
|
|
1113
|
-
endpoint: explicitEndpoint ?? bootstrapSummary?.config?.endpoint_prefix ??
|
|
1202
|
+
endpoint: explicitEndpoint ?? bootstrapSummary?.config?.endpoint_prefix ?? DEFAULT_ENDPOINT,
|
|
1114
1203
|
urlPrefix: "",
|
|
1115
1204
|
cacheTtl: void 0,
|
|
1116
1205
|
levelRoutes: {}
|
|
1117
1206
|
};
|
|
1118
|
-
const discoveryInputs = { explicitLevels, explicitEager, explicitEndpoint };
|
|
1207
|
+
const discoveryInputs = { explicitLevels, explicitEager, explicitEndpoint, warnings };
|
|
1119
1208
|
let autoDiscoveryCompleted = false;
|
|
1120
1209
|
let resolveReady;
|
|
1121
1210
|
let rejectReady;
|
|
@@ -1125,30 +1214,30 @@ function createRouteForge(options) {
|
|
|
1125
1214
|
});
|
|
1126
1215
|
readyPromise.catch(() => {
|
|
1127
1216
|
});
|
|
1217
|
+
let readySettledOk = false;
|
|
1218
|
+
readyPromise.then(
|
|
1219
|
+
() => {
|
|
1220
|
+
readySettledOk = true;
|
|
1221
|
+
},
|
|
1222
|
+
() => {
|
|
1223
|
+
}
|
|
1224
|
+
);
|
|
1128
1225
|
const cacheTtl = cacheOpts.ttl ?? DEFAULT_CACHE_TTL;
|
|
1129
1226
|
const cacheStorage = cacheOpts.storage ?? "memory";
|
|
1130
1227
|
const cache = new RouteCache({ storage: cacheStorage, ttl: cacheTtl });
|
|
1131
1228
|
const requestInterceptors = new InterceptorManagerImpl();
|
|
1132
1229
|
const responseInterceptors = new InterceptorManagerImpl();
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
const [onFulfilled, onRejected] = entry;
|
|
1139
|
-
requestInterceptors.use(onFulfilled, onRejected);
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1230
|
+
const reqDecl = normalizeInterceptorDeclaration(
|
|
1231
|
+
declarativeInterceptors?.request
|
|
1232
|
+
);
|
|
1233
|
+
if (reqDecl.onFulfilled || reqDecl.onRejected) {
|
|
1234
|
+
requestInterceptors.use(reqDecl.onFulfilled, reqDecl.onRejected);
|
|
1142
1235
|
}
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
const [onFulfilled, onRejected] = entry;
|
|
1149
|
-
responseInterceptors.use(onFulfilled, onRejected);
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1236
|
+
const resDecl = normalizeInterceptorDeclaration(
|
|
1237
|
+
declarativeInterceptors?.response
|
|
1238
|
+
);
|
|
1239
|
+
if (resDecl.onFulfilled || resDecl.onRejected) {
|
|
1240
|
+
responseInterceptors.use(resDecl.onFulfilled, resDecl.onRejected);
|
|
1152
1241
|
}
|
|
1153
1242
|
const adapterPromise = resolveAdapter({
|
|
1154
1243
|
adapter,
|
|
@@ -1160,6 +1249,11 @@ function createRouteForge(options) {
|
|
|
1160
1249
|
if (!adapterResolved) {
|
|
1161
1250
|
adapterObj = await adapterPromise.catch((e) => {
|
|
1162
1251
|
if (e instanceof AdapterNotFoundError) throw e;
|
|
1252
|
+
if (warnings) {
|
|
1253
|
+
console.warn(
|
|
1254
|
+
`[route-forge] adapter initialization failed (${e?.message ?? String(e)}); falling back to builtin`
|
|
1255
|
+
);
|
|
1256
|
+
}
|
|
1163
1257
|
return resolveAdapter({
|
|
1164
1258
|
adapter: "builtin",
|
|
1165
1259
|
forgeInterceptors: { request: requestInterceptors, response: responseInterceptors }
|
|
@@ -1171,10 +1265,7 @@ function createRouteForge(options) {
|
|
|
1171
1265
|
}
|
|
1172
1266
|
function assertDiscoveryReady() {
|
|
1173
1267
|
if (!autoDiscoveryCompleted && !explicitLevels?.length) {
|
|
1174
|
-
throw new
|
|
1175
|
-
"Route data not available. Auto-discovery has not completed. Use forge.ready() or forge.use(level) first.",
|
|
1176
|
-
{ code: "RF_FE_010" }
|
|
1177
|
-
);
|
|
1268
|
+
throw new DiscoveryNotReadyError();
|
|
1178
1269
|
}
|
|
1179
1270
|
}
|
|
1180
1271
|
async function fetchMeta(routeTag, url, level = "") {
|
|
@@ -1199,8 +1290,8 @@ function createRouteForge(options) {
|
|
|
1199
1290
|
const resp = await doRawRequest(config);
|
|
1200
1291
|
if (!resp || resp.status < 200 || resp.status >= 300) {
|
|
1201
1292
|
throw new HTTPError(
|
|
1202
|
-
`Failed to fetch "${routeTag}": HTTP ${resp?.status}`,
|
|
1203
|
-
{ level, status: resp?.status, url, method: "GET" }
|
|
1293
|
+
`Failed to fetch "${routeTag}" (${url}): HTTP ${resp?.status}`,
|
|
1294
|
+
{ level, status: resp?.status, url, method: "GET", response: resp ?? void 0 }
|
|
1204
1295
|
);
|
|
1205
1296
|
}
|
|
1206
1297
|
return resp.data;
|
|
@@ -1237,11 +1328,14 @@ function createRouteForge(options) {
|
|
|
1237
1328
|
function getRoutes(level) {
|
|
1238
1329
|
return level === void 0 ? store.getRoutes() : store.getRoutes(level);
|
|
1239
1330
|
}
|
|
1331
|
+
function getLevels() {
|
|
1332
|
+
return [...discoveryState.levels];
|
|
1333
|
+
}
|
|
1240
1334
|
function route(level, name, params) {
|
|
1241
1335
|
assertDiscoveryReady();
|
|
1242
1336
|
const meta = findRouteMeta(level, name);
|
|
1243
1337
|
if (!meta) {
|
|
1244
|
-
throw new UnknownRouteError(name, level);
|
|
1338
|
+
throw new UnknownRouteError(name, level, Object.keys(store.getRoutes(level)));
|
|
1245
1339
|
}
|
|
1246
1340
|
return buildRequestUrl(meta, params ?? {}, { baseURL, urlPrefix: discoveryState.urlPrefix });
|
|
1247
1341
|
}
|
|
@@ -1251,6 +1345,7 @@ function createRouteForge(options) {
|
|
|
1251
1345
|
responseInterceptors,
|
|
1252
1346
|
load,
|
|
1253
1347
|
findRouteMeta,
|
|
1348
|
+
getRouteNames: (lvl) => Object.keys(store.getRoutes(lvl)),
|
|
1254
1349
|
baseURL,
|
|
1255
1350
|
state: discoveryState,
|
|
1256
1351
|
timeout,
|
|
@@ -1306,7 +1401,10 @@ function createRouteForge(options) {
|
|
|
1306
1401
|
isLoaded,
|
|
1307
1402
|
hasRoute,
|
|
1308
1403
|
getRoutes,
|
|
1404
|
+
getLevels,
|
|
1405
|
+
warnings,
|
|
1309
1406
|
isLoading: () => loadingTracker.isLoading(),
|
|
1407
|
+
isReady: () => readySettledOk,
|
|
1310
1408
|
onLoadingChange: (cb) => loadingTracker.subscribe(cb),
|
|
1311
1409
|
interceptors: {
|
|
1312
1410
|
request: requestInterceptors,
|
|
@@ -1321,6 +1419,6 @@ function createRouteForge(options) {
|
|
|
1321
1419
|
return forgeInstance;
|
|
1322
1420
|
}
|
|
1323
1421
|
|
|
1324
|
-
export { AdapterNotFoundError, ForgeError, HTTPError, InterceptorManagerImpl, InvalidInterceptorReturnError, LoadingTracker, MissingRouteParamError, NetworkError, RequestAbortedError, RouteCache, UnknownLevelError, UnknownRouteError, createInterceptorManager, createRouteForge, resolveRouteName, resolveRouteNameSync };
|
|
1422
|
+
export { AdapterNotFoundError, DiscoveryNotReadyError, ForgeError, HTTPError, InterceptorManagerImpl, InvalidInterceptorReturnError, InvalidPathParamError, LoadingTracker, MissingRouteParamError, NetworkError, RequestAbortedError, RouteCache, UnknownLevelError, UnknownRouteError, createInterceptorManager, createRouteForge, resolveRouteName, resolveRouteNameSync };
|
|
1325
1423
|
//# sourceMappingURL=index.js.map
|
|
1326
1424
|
//# sourceMappingURL=index.js.map
|