@route-forge/core 2.2.1 → 3.1.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.d.ts CHANGED
@@ -1,5 +1,497 @@
1
- import { a as RouteForgeOptions, b as RouteForge, I as InterceptorManager, c as InterceptorHandler, C as CacheStorage, R as RouteMeta, L as LevelRoutesResponse } from './types-CDKE8rw-.js';
2
- export { A as AdapterOption, d as ApiCallParams, B as BoundForge, F as Fetcher, e as ForgeApiParams, f as ForgeApiResponse, g as ForgeRequest, h as ForgeRouteMap, i as ForgeRouteName, j as LoadingChangeCallback, k as LoadingChangeEvent, l as LoadingTracker, m as RequestConfig, n as ResponseData, S as SummaryResponse, U as UseForgeApiBoundCall, o as UseForgeApiBoundReturn, p as UseForgeApiCall, q as UseForgeApiReturn } from './types-CDKE8rw-.js';
1
+ import { R as RouteMeta, S as SummaryResponse, C as CacheStorage, L as LevelRoutesResponse } from './manifest-bjy4P_B4.js';
2
+
3
+ /**
4
+ * 请求 / 响应 HTTP 层类型(拦截器、adapter、api 调用参数共用)
5
+ * @see .docs/SPEC.md §4.1.3a, §4.3
6
+ */
7
+
8
+ /**
9
+ * 请求拦截器接收/返回的配置对象(可变,返回修改后的版本)
10
+ */
11
+ interface RequestConfig {
12
+ route: string;
13
+ level: string;
14
+ method: string;
15
+ url: string;
16
+ headers: Record<string, string>;
17
+ body?: unknown;
18
+ params: Record<string, unknown>;
19
+ meta: RouteMeta;
20
+ /** 请求超时毫秒数 */
21
+ timeout?: number;
22
+ /** 自定义 query 序列化函数 */
23
+ paramsSerializer?: (params: Record<string, unknown>) => string;
24
+ /** 请求取消信号(AbortSignal),用于取消已发出的请求 */
25
+ signal?: AbortSignal;
26
+ }
27
+ /**
28
+ * 响应拦截器首段接收的完整数据对象
29
+ */
30
+ interface ResponseData {
31
+ route: string;
32
+ level: string;
33
+ method: string;
34
+ url: string;
35
+ status: number;
36
+ headers: Headers;
37
+ data: unknown;
38
+ config: RequestConfig;
39
+ }
40
+ /**
41
+ * forge.api() 返回的可取消请求对象。
42
+ * 继承 Promise,附加 abort() 方法用于取消请求。
43
+ * 内部自动创建 AbortController,用户无需手动管理。
44
+ */
45
+ interface ForgeRequest<T = unknown> extends Promise<T> {
46
+ /** 取消请求。调用后请求将被中止,Promise reject 为 RequestAbortedError */
47
+ abort(): void;
48
+ }
49
+ /**
50
+ * forge.api(level, name, params) 调用参数
51
+ *
52
+ * 参数解析规则(智能消解):
53
+ * 1. `params` — 显式指定路径参数,优先级最高
54
+ * 2. 平铺的 string | number 值 — 作为路径参数(含与 query/body/headers 同名的 key)
55
+ * 3. `query` (对象) — 查询参数,序列化到 URL query string
56
+ * 4. `body` (非 string/number) — 请求体
57
+ * 5. `headers` (对象) — 自定义请求头
58
+ *
59
+ * 当路径参数名与 query/body/headers 冲突时:
60
+ * - 值为 string | number → 智能识别为路径参数
61
+ * - 同时提供 params 显式指定 → params 优先,固定 key 按原定义处理
62
+ */
63
+ interface ApiCallParams {
64
+ /** 路径参数:填充到 URI 模板的 {name} 占位符 */
65
+ [paramName: string]: unknown;
66
+ /** 显式指定路径参数(优先级最高,解决路径参数名与 query/body/headers 冲突的场景) */
67
+ params?: Record<string, unknown>;
68
+ /**
69
+ * 查询参数(对象 → query string)或路径参数(string | number → 填充 {query} 占位符)
70
+ * @see .docs/SPEC.md §4.1.3 参数智能解析
71
+ */
72
+ query?: Record<string, unknown> | string | number;
73
+ /**
74
+ * 请求体(非基元值 → body)或路径参数(string | number → 填充 {body} 占位符)
75
+ */
76
+ body?: unknown;
77
+ /**
78
+ * 自定义请求头(对象 → headers)或路径参数(string | number → 填充 {headers} 占位符)
79
+ */
80
+ headers?: Record<string, string> | string | number;
81
+ /**
82
+ * 单次请求超时覆盖(毫秒);不传时使用 createRouteForge({ timeout }) 全局值
83
+ */
84
+ timeout?: number;
85
+ /**
86
+ * 外部取消信号(固定 key,恒不参与路径参数)。信号触发时请求被取消
87
+ * (reject 为 RequestAbortedError),与返回值自带的 `abort()` 联合生效——任一取消即中止。
88
+ * 若传入时 signal 已 abort,则直接短路、不发请求。适用于组件卸载 / React Query / AbortController 等外部生命周期。
89
+ */
90
+ signal?: AbortSignal;
91
+ }
92
+ /**
93
+ * Adapter 选择值
94
+ */
95
+ type AdapterOption = 'auto' | 'axios' | 'builtin' | Fetcher;
96
+ /**
97
+ * Fetcher 接口(自定义 adapter)
98
+ * @see .docs/SPEC.md §4.3.3
99
+ */
100
+ interface Fetcher {
101
+ request(config: RequestConfig): Promise<ResponseData>;
102
+ interceptors?: {
103
+ request?: InterceptorManager<RequestConfig, RequestConfig>;
104
+ response?: InterceptorManager<ResponseData, unknown>;
105
+ };
106
+ }
107
+ /**
108
+ * 拦截器管理器接口(与 axios use/eject/clear API 一致)
109
+ *
110
+ * 双类型参数说明(对应 SPEC §4.1.3a):
111
+ * - 请求拦截:TIn = TOut = RequestConfig(不可变换类型,仅修改字段)
112
+ * - 响应拦截:TIn = ResponseData, TOut = unknown(首段接收 ResponseData,
113
+ * 后续段接收上一段返回值,返回类型由用户自行约束)
114
+ */
115
+ interface InterceptorManager<TIn, TOut = TIn> {
116
+ use(onFulfilled?: (value: TIn) => TOut | Promise<TOut>, onRejected?: (error: unknown) => unknown | Promise<unknown>): number;
117
+ eject(id: number): void;
118
+ clear(): void;
119
+ /** 内部使用:当前已注册拦截器快照 */
120
+ forEach(fn: (handler: InterceptorHandler<TIn, TOut>) => void): void;
121
+ }
122
+ /**
123
+ * 单个拦截器内部结构
124
+ */
125
+ interface InterceptorHandler<TIn, TOut = TIn> {
126
+ id: number;
127
+ onFulfilled?: (value: TIn) => TOut | Promise<TOut>;
128
+ onRejected?: (error: unknown) => unknown | Promise<unknown>;
129
+ }
130
+
131
+ /**
132
+ * 二级路由类型映射与推断条件类型
133
+ *
134
+ * 声明 `ForgeRouteMap`(codegen 生成或 module augmentation)后,
135
+ * api / route / hasRoute 的 name、params、响应类型按映射收敛;未声明时全部回退宽松类型。
136
+ */
137
+
138
+ /**
139
+ * 二级路由类型映射(可由 codegen 生成或通过 module augmentation 增强)
140
+ *
141
+ * @example
142
+ * declare module '@route-forge/core' {
143
+ * interface ForgeRouteMap {
144
+ * admin: {
145
+ * 'users.show': { method: 'GET'; params: { user: string | number }; response: User };
146
+ * 'users.index': { method: 'GET'; params: {}; response: User[] };
147
+ * };
148
+ * public: {
149
+ * 'login.show': { method: 'GET'; params: {}; response: unknown };
150
+ * };
151
+ * }
152
+ * }
153
+ */
154
+ interface ForgeRouteMap {
155
+ }
156
+ /** 从 ForgeRouteMap 推断指定层级下的路由名;未定义时回退 string */
157
+ type ForgeRouteName<L extends string> = [
158
+ keyof ForgeRouteMap
159
+ ] extends [never] ? string : L extends keyof ForgeRouteMap ? keyof ForgeRouteMap[L] & string : string;
160
+ /** 从 ForgeRouteMap 推断指定路由的 params 类型;未定义时回退 ApiCallParams */
161
+ type ForgeApiParams<L extends string, N extends string> = [
162
+ keyof ForgeRouteMap
163
+ ] extends [never] ? ApiCallParams : L extends keyof ForgeRouteMap ? N extends keyof ForgeRouteMap[L] ? (ForgeRouteMap[L][N] extends {
164
+ params: infer P;
165
+ } ? P & ApiCallParams : ApiCallParams) : ApiCallParams : ApiCallParams;
166
+ /** 从 ForgeRouteMap 推断指定路由的响应类型;未定义时回退 unknown */
167
+ type ForgeApiResponse<L extends string, N extends string> = [
168
+ keyof ForgeRouteMap
169
+ ] extends [never] ? unknown : L extends keyof ForgeRouteMap ? N extends keyof ForgeRouteMap[L] ? (ForgeRouteMap[L][N] extends {
170
+ response: infer R;
171
+ } ? R : unknown) : unknown : unknown;
172
+
173
+ /**
174
+ * LoadingTracker:加载中标识状态管理
175
+ *
176
+ * 通过引用计数器跟踪并发请求数。
177
+ * - start():计数器 +1,进入加载状态
178
+ * - stop():计数器 -1,归零时退出加载状态
179
+ * - isLoading():查询当前是否处于加载中
180
+ * - subscribe(cb):监听状态变化,返回取消订阅函数
181
+ *
182
+ * @see .docs/SPEC.md §4.1.8
183
+ */
184
+ /** 状态变更回调签名 */
185
+ type LoadingChangeCallback = (event: LoadingChangeEvent) => void;
186
+ /** 状态变更事件 */
187
+ interface LoadingChangeEvent {
188
+ /** 当前是否仍处于加载中 */
189
+ loading: boolean;
190
+ /** 当前并发请求数 */
191
+ count: number;
192
+ }
193
+ /**
194
+ * 加载状态跟踪器
195
+ *
196
+ * 单一计数器,跟踪所有 API 请求的并发数。
197
+ * 不绑定任何 UI 样式,仅提供状态供框架层或业务层消费。
198
+ */
199
+ declare class LoadingTracker {
200
+ /** 当前并发请求计数 */
201
+ private count;
202
+ /** 订阅者集合 */
203
+ private subscribers;
204
+ /**
205
+ * 开始一次加载(计数器 +1)
206
+ */
207
+ start(): void;
208
+ /**
209
+ * 结束一次加载(计数器 -1)
210
+ */
211
+ stop(): void;
212
+ /**
213
+ * 查询当前是否处于加载中
214
+ */
215
+ isLoading(): boolean;
216
+ /**
217
+ * 获取当前并发计数
218
+ */
219
+ getCount(): number;
220
+ /**
221
+ * 订阅加载状态变更
222
+ * @returns 取消订阅函数
223
+ */
224
+ subscribe(cb: LoadingChangeCallback): () => void;
225
+ /** 通知所有订阅者 */
226
+ private notify;
227
+ }
228
+
229
+ /**
230
+ * RouteChangeTracker:路由表数据变更订阅(供框架层在缓存刷新后重算响应式 URL)
231
+ *
232
+ * 与 LoadingTracker(跟踪在途请求数)正交:本跟踪器表达的是「某层级的路由元信息内容已变化」
233
+ * ——发生在层级数据成功写入缓存(首次 load / revalidate)或失效(invalidate)之后。
234
+ *
235
+ * - notify(level):广播某层级数据已变更(带 level,订阅者按自身绑定的 level 过滤,避免全量重渲染)
236
+ * - subscribe(cb):订阅变更,返回取消订阅函数
237
+ *
238
+ * @see .docs/SPEC.md §4.1.8
239
+ */
240
+ /** 路由表数据变更回调签名;level 为发生变化的层级 */
241
+ type RouteChangeCallback = (level: string) => void;
242
+ /**
243
+ * 路由数据变更广播器:微任务合批投递,避免同一 tick 内多次变更(invalidate-all、并发 load)
244
+ * 触发同步惊群,并把订阅者回调移出 cache.write 的关键路径。
245
+ */
246
+ declare class RouteChangeTracker {
247
+ private readonly subscribers;
248
+ /** 本微任务周期内累积的变更层级(去重) */
249
+ private readonly pending;
250
+ /** 是否已排定一次微任务 flush */
251
+ private scheduled;
252
+ /** 订阅路由表数据变更;返回取消订阅函数 */
253
+ subscribe(cb: RouteChangeCallback): () => void;
254
+ /** 记录某层级数据已变更;同一 tick 多次调用合并为一次投递(每层级各投一次) */
255
+ notify(level: string): void;
256
+ /** 一次性投递本周期累积的所有变更层级;单订阅者抛错不影响其它 */
257
+ private flush;
258
+ }
259
+
260
+ /**
261
+ * forge 顶层 API 形状、配置项、BoundForge 与 useForgeApi 返回类型
262
+ * @see .docs/SPEC.md §4.1.6, §4.1.7, §5.2
263
+ */
264
+
265
+ /**
266
+ * forge 顶层 API 形状
267
+ */
268
+ interface RouteForge {
269
+ /**
270
+ * 通过层级 + 路由名调用 API;level 用于确定加载哪个层级的路由元信息。
271
+ * 声明 `ForgeRouteMap`(codegen 生成或 module augmentation)后,name / params / 响应类型
272
+ * 按映射收敛;未声明映射时完全等价于 `(level: string, name: string, params?: ApiCallParams) => ForgeRequest<unknown>`。
273
+ */
274
+ api<L extends string, N extends ForgeRouteName<L>>(level: L, name: N, params?: ForgeApiParams<L, N>): ForgeRequest<ForgeApiResponse<L, N>>;
275
+ /** 拉取一个或多个层级(自动并发去重) */
276
+ load(level: string | string[]): Promise<void>;
277
+ /**
278
+ * 强制刷新一个或多个层级:跳过缓存命中短路重新拉取,成功覆盖缓存、失败保留旧值。
279
+ * 与 `invalidate` + `load` 不同——全程不清空缓存,读取旧数据不受影响、无空窗。
280
+ * 刷新成功会经 `onRoutesChange` 广播该层级变更;失败时 Promise reject 携带拉取错误。
281
+ */
282
+ revalidate(level: string | string[]): Promise<void>;
283
+ /**
284
+ * 仅生成 URL,不发请求;level 用于定位路由所在的层级缓存。
285
+ * 声明 `ForgeRouteMap` 后 name 按映射收敛(params 保持宽松——路径参数与后端默认值均可)。
286
+ */
287
+ route<L extends string, N extends ForgeRouteName<L>>(level: L, name: N, params?: Record<string, unknown>): string;
288
+ /** route() 的语义别名,适用于链接生成等场景 */
289
+ url<L extends string, N extends ForgeRouteName<L>>(level: L, name: N, params?: Record<string, unknown>): string;
290
+ /**
291
+ * 失效缓存:
292
+ * - invalidate():失效全部层级
293
+ * - invalidate('admin'):失效指定层级
294
+ * - invalidate(['admin', 'manage']):批量失效指定层级
295
+ */
296
+ invalidate(level?: string | string[]): void;
297
+ /** 检查指定层级路由是否已加载并缓存;不传参检查全部 */
298
+ isLoaded(level?: string): boolean;
299
+ /** 检查指定层级下某路由是否存在(需该层级缓存已加载);声明 `ForgeRouteMap` 后 name 按映射收敛 */
300
+ hasRoute<L extends string, N extends ForgeRouteName<L>>(level: L, name: N): boolean;
301
+ /** 查询加载中标识状态 */
302
+ isLoading(): boolean;
303
+ /**
304
+ * ready() 是否已成功 resolve(同步查询,不触发任何加载)。
305
+ * discovery + eager 完成为 true;reject 不算就绪(保持 false)。
306
+ * 供框架层 ready 门闩(react Provider `gate` / vue `ForgeReady`)避免多余的 fallback 首帧。
307
+ */
308
+ isReady(): boolean;
309
+ /** 非致命警告是否启用(来自 createRouteForge({ warnings }),默认 true);vue/react 适配层共用此开关 */
310
+ readonly warnings: boolean;
311
+ /** 订阅加载状态变更,返回取消订阅函数 */
312
+ onLoadingChange(cb: LoadingChangeCallback): () => void;
313
+ /**
314
+ * 订阅路由表数据变更:层级数据成功写入(load / revalidate)或失效(invalidate)后,
315
+ * 回调携带发生变化的层级。框架层据此重算受影响的响应式 URL(后台刷新无需刷新页面即热更新)。
316
+ * @returns 取消订阅函数
317
+ */
318
+ onRoutesChange(cb: RouteChangeCallback): () => void;
319
+ /**
320
+ * 获取路由元信息快照(深拷贝,修改返回值不影响内部缓存)。
321
+ * - getRoutes(level):返回指定层级下全部路由;层级未声明抛 `UnknownLevelError`,
322
+ * 已声明但未加载返回 `{}`
323
+ * - getRoutes():返回全部层级的路由(按 level 分组)
324
+ */
325
+ getRoutes(level: string): Record<string, RouteMeta>;
326
+ getRoutes(): Record<string, Record<string, RouteMeta>>;
327
+ /**
328
+ * 当前已知的已声明层级列表(含后端恒注入的 `unassigned`)。
329
+ * 内嵌 / `summary` 引导:构造后即可用;网络引导:`ready()` 前可能为空数组、之后为全量。
330
+ * 只读发现 API,不触发加载、未就绪不抛错(返回 `[]`)。
331
+ */
332
+ getLevels(): string[];
333
+ /** 拦截器入口(请求 / 响应) */
334
+ interceptors: {
335
+ request: InterceptorManager<RequestConfig, RequestConfig>;
336
+ response: InterceptorManager<ResponseData, unknown>;
337
+ };
338
+ /**
339
+ * auto-discovery + eager load 完成后 resolve。
340
+ * 始终返回 Promise<this>,resolve 值为 forge 实例自身,支持链式调用。
341
+ *
342
+ * - 无参:返回 Promise,适合 async/await
343
+ * - 有参:回调内部走 then/catch,仍返回 Promise
344
+ */
345
+ ready(): Promise<RouteForge>;
346
+ ready(onFulfilled: (forge: RouteForge) => void, onRejected?: (error: unknown) => void): Promise<RouteForge>;
347
+ /**
348
+ * 绑定 level(+ 可选 prefix),返回 BoundForge。
349
+ * 唯一入口 — Vue/React/IIFE 共享同一套 API 表面。
350
+ *
351
+ * - use():不绑定,返回 RouteForge 自身
352
+ * - use(level):绑定 level
353
+ * - use(level, prefix):绑定 level + prefix
354
+ */
355
+ use(): RouteForge;
356
+ use<L extends string>(level: L, prefix?: string): BoundForge;
357
+ }
358
+ /**
359
+ * createRouteForge 配置项
360
+ * @see .docs/SPEC.md §5.2
361
+ */
362
+ interface RouteForgeOptions {
363
+ /**
364
+ * 摘要端点 URL(网络拉取来源)。
365
+ * 摘要数据源级联(SPEC §4.1.1):Blade 注入的 `window.__ROUTE_FORGE__` > 本 `summary` 字段 > 网络拉取 `endpoint`。
366
+ * 命中前两者时可省略;层级明细端点取自摘要 `levels[].route.uri`,不依赖本字段。
367
+ * 三者皆无(既无注入/summary、又无 endpoint)时网络引导回退默认摘要端点 `/_forge/routes`(DEFAULT_ENDPOINT)。
368
+ */
369
+ endpoint?: string;
370
+ /**
371
+ * 直接提供摘要数据(SummaryResponse),跳过摘要 HTTP 往返——用于测试或非 Blade 的注入式引导。
372
+ * 优先级低于页面内嵌的 `window.__ROUTE_FORGE__`(存在时以后端真值为准)。
373
+ * @see .docs/SPEC.md §4.1.1 / §3.1.8
374
+ */
375
+ summary?: SummaryResponse;
376
+ /**
377
+ * 层级列表。未传时从摘要自动发现(SPEC §4.1.1)。
378
+ * 显式传入时取与摘要响应 levels 键的交集(前端不能声明后端不存在的层级,SPEC §5.3)。
379
+ */
380
+ levels?: string[];
381
+ eager?: string[];
382
+ adapter?: AdapterOption;
383
+ cache?: {
384
+ ttl?: number;
385
+ storage?: CacheStorage;
386
+ };
387
+ interceptors?: {
388
+ /**
389
+ * 声明式请求拦截器,只描述**一个**拦截器,支持三种写法(SPEC §4.1.1):
390
+ * - 函数 `resolve` → 视为 onFulfilled
391
+ * - 元组 `[resolve?, reject?]` → 成功 / 失败(允许缺位,如 `[resolve]`、`[undefined, reject]`)
392
+ * - 对象 `{ resolve?, reject? }` → 具名成功 / 失败
393
+ * 需要注册多个拦截器请改用运行时 `forge.interceptors.request.use()`(可多次调用)。
394
+ */
395
+ request?: ((c: RequestConfig) => RequestConfig | Promise<RequestConfig>) | [
396
+ ((c: RequestConfig) => RequestConfig | Promise<RequestConfig>)?,
397
+ ((e: unknown) => unknown | Promise<unknown>)?
398
+ ] | {
399
+ resolve?: (c: RequestConfig) => RequestConfig | Promise<RequestConfig>;
400
+ reject?: (e: unknown) => unknown | Promise<unknown>;
401
+ };
402
+ /**
403
+ * 声明式响应拦截器,形状同 `request`(首段 onFulfilled 接收 ResponseData)。
404
+ * 同样只描述一个拦截器,多拦截器改用运行时 `forge.interceptors.response.use()`。
405
+ */
406
+ response?: ((r: ResponseData) => unknown | Promise<unknown>) | [((r: ResponseData) => unknown | Promise<unknown>)?, ((e: unknown) => unknown | Promise<unknown>)?] | {
407
+ resolve?: (r: ResponseData) => unknown | Promise<unknown>;
408
+ reject?: (e: unknown) => unknown | Promise<unknown>;
409
+ };
410
+ };
411
+ /**
412
+ * @deprecated 前端校验始终开启,此选项不再被消费。
413
+ * 前端在层级未声明时始终抛 `UnknownLevelError`、路由名不存在始终抛 `UnknownRouteError`、
414
+ * 必填路径参数缺失始终抛 `MissingRouteParamError` —— 校验行为与 strict 无关,静默忽略会掩盖拼写错误、难以排查。
415
+ * 后端 `strict_mode` 的宽松/严格语义(未命中层级路由是否归入 unassigned/fallback)由后端在生成 manifest 时决定。
416
+ * 字段保留仅为向后兼容,传入不会有任何效果。
417
+ */
418
+ strict?: boolean;
419
+ timeout?: number;
420
+ baseURL?: string;
421
+ /**
422
+ * 非致命警告开关(默认 true):控制 core 内部的 `console.warn`(如显式 levels 降级、
423
+ * endpoint_prefix 覆盖、schemeVersion 兼容提示等)。`false` 时静音这些 warn——
424
+ * `console.error` 级输出(如 eager 层级加载失败)不受影响,错误永远响亮。
425
+ * 该值以只读字段 `RouteForge.warnings` 暴露,vue/react 适配层的渲染期降级警告同样遵循它。
426
+ */
427
+ warnings?: boolean;
428
+ }
429
+ /**
430
+ * 已绑定 level 的 forge 对象。
431
+ * 由 `forge.use(level, prefix?)` 返回,Vue/React/IIFE 共享同一 API 表面。
432
+ *
433
+ * @typeParam LL - levelLoaded 的类型:core 默认 Promise<void>,Vue 替换为 Ref<boolean>
434
+ */
435
+ interface BoundForge<LL = Promise<void>> {
436
+ /** 直接调用 = api 快捷方式,自动带绑定的 level */
437
+ (name: string, params?: ApiCallParams): ForgeRequest;
438
+ /** 当前绑定的 level */
439
+ readonly level: string;
440
+ /** 绑定的路由名前缀(仅传入 prefix 时存在) */
441
+ readonly prefix?: string;
442
+ /** level 加载状态(core: Promise<void>,Vue: Ref<boolean>) */
443
+ levelLoaded: LL;
444
+ api(name: string, params?: ApiCallParams): ForgeRequest;
445
+ route(name: string, params?: Record<string, unknown>): string;
446
+ url(name: string, params?: Record<string, unknown>): string;
447
+ hasRoute(name: string): boolean;
448
+ getRoutes(): Record<string, RouteMeta>;
449
+ load(): Promise<void>;
450
+ invalidate(): void;
451
+ isLoaded(): boolean;
452
+ isLoading(): boolean;
453
+ onLoadingChange(cb: LoadingChangeCallback): () => void;
454
+ /** 等待绑定的 level 加载完成,resolve 值为自身(BoundForge),保证可安全调用 */
455
+ onLevelLoaded(): Promise<BoundForge<LL>>;
456
+ onLevelLoaded(onFulfilled: (bound: BoundForge<LL>) => void, onRejected?: (error: unknown) => void): Promise<BoundForge<LL>>;
457
+ /** 在已绑定 level 基础上追加/替换 prefix,返回新的 BoundForge */
458
+ useRoutePrefix(prefix: string): BoundForge<LL>;
459
+ }
460
+ /** call 函数签名 — 未绑定 level,需要显式传入 */
461
+ interface UseForgeApiCall {
462
+ (level: string, name: string, params?: ApiCallParams): Promise<{
463
+ data: unknown;
464
+ error: unknown;
465
+ }>;
466
+ }
467
+ /** call 函数签名 — 已绑定 level,无需再传 */
468
+ interface UseForgeApiBoundCall<L extends string> {
469
+ (name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): Promise<{
470
+ data: ForgeApiResponse<L, ForgeRouteName<L>>;
471
+ error: unknown;
472
+ }>;
473
+ }
474
+ /**
475
+ * useForgeApi 返回类型 — 未绑定 level
476
+ * @typeParam PendingType - 框架层 pending 状态类型(Vue: Ref<boolean>, React: boolean)
477
+ * @typeParam ErrorType - 框架层 error 状态类型(Vue: Ref<unknown>, React: unknown)
478
+ */
479
+ interface UseForgeApiReturn<PendingType = unknown, ErrorType = unknown> {
480
+ pending: PendingType;
481
+ error: ErrorType;
482
+ call: UseForgeApiCall;
483
+ }
484
+ /**
485
+ * useForgeApi 返回类型 — 已绑定 level
486
+ * @typeParam L - 层级名
487
+ * @typeParam PendingType - 框架层 pending 状态类型
488
+ * @typeParam ErrorType - 框架层 error 状态类型
489
+ */
490
+ interface UseForgeApiBoundReturn<L extends string, PendingType = unknown, ErrorType = unknown> {
491
+ pending: PendingType;
492
+ error: ErrorType;
493
+ call: UseForgeApiBoundCall<L>;
494
+ }
3
495
 
4
496
  /**
5
497
  * Route Forge 主入口:createRouteForge
@@ -16,23 +508,10 @@ export { A as AdapterOption, d as ApiCallParams, B as BoundForge, F as Fetcher,
16
508
  declare function createRouteForge(options?: RouteForgeOptions): RouteForge;
17
509
 
18
510
  /**
19
- * 拦截器管理器实现
20
- * @see .docs/SPEC.md §4.1.3a, §4.1.1
21
- *
22
- * 执行顺序约定(对齐 axios):
23
- * - 请求拦截器:LIFO(后注册先执行),onRejected 与 onFulfilled 同序
24
- * - 响应拦截器:FIFO(先注册先执行),onRejected 与 onFulfilled 同序
25
- *
26
- * 实现策略:
27
- * - InterceptorManagerImpl.forEach 保持正序迭代(与 use/eject 语义一致)
28
- * - runRequestInterceptors 收集 handlers 后 reverse() 再串联 Promise 链,实现 LIFO
29
- * - runResponseInterceptors 直接正序串联,实现 FIFO
511
+ * 拦截器管理器实现:use/eject/clear/forEach 的注册与快照存储(不含执行编排)。
512
+ * @see .docs/SPEC.md §4.1.3a
30
513
  *
31
- * 串联实现:采用标准 Promise 链语义
32
- * `Promise.resolve(initial).then(f0, r0).then(f1, r1).then(f2, r2)...`
33
- * - onFulfilled 抛错 → 下一组 onRejected 接住
34
- * - onRejected 返回值 → 后续 onFulfilled 继续执行(恢复为正常流程)
35
- * - onRejected 抛错 → 下一组 onRejected 接住 / 进入调用方 catch
514
+ * 执行顺序编排见 interceptors/runner.ts;创建时声明式入参归一见 interceptors/normalize.ts。
36
515
  */
37
516
 
38
517
  declare class InterceptorManagerImpl<TIn, TOut = TIn> implements InterceptorManager<TIn, TOut> {
@@ -118,6 +597,8 @@ declare class RouteCache {
118
597
  interface RouteResolver {
119
598
  load(level: string | string[]): Promise<void>;
120
599
  hasRoute(level: string, name: string): boolean;
600
+ /** 可选:该层级当前已加载的路由名列表(UnknownRouteError 附候选值用) */
601
+ getRouteNames?(level: string): string[];
121
602
  }
122
603
  /**
123
604
  * 异步版本:先确保层级已加载,再做歧义消解。
@@ -134,6 +615,7 @@ declare function resolveRouteNameSync(forge: RouteResolver, level: string, prefi
134
615
  * Route Forge 错误基类与具体错误类
135
616
  * @see .docs/SPEC.md §6
136
617
  */
618
+
137
619
  interface ForgeErrorContext {
138
620
  [key: string]: unknown;
139
621
  }
@@ -158,15 +640,19 @@ declare class ForgeError extends Error {
158
640
  }
159
641
  /** RF_FE_001:路由名不存在于已加载层级中 */
160
642
  declare class UnknownRouteError extends ForgeError {
161
- constructor(route: string, level?: string);
643
+ constructor(route: string, level?: string, candidates?: string[]);
162
644
  }
163
645
  /** RF_FE_002:路由所在层级未在 levels 声明 */
164
646
  declare class UnknownLevelError extends ForgeError {
165
- constructor(level: string);
647
+ constructor(level: string, candidates?: string[]);
166
648
  }
167
- /** RF_FE_003:路径参数缺失(strict=true 时) */
649
+ /** RF_FE_003:必填路径参数缺失(无后端 default 时,前端校验恒开) */
168
650
  declare class MissingRouteParamError extends ForgeError {
169
- constructor(route: string, missingParams: string[]);
651
+ constructor(route: string, missingParams: string[], uri?: string);
652
+ }
653
+ /** RF_FE_003:路径参数收到非原始值(对象/数组等,无法安全插入 URI) */
654
+ declare class InvalidPathParamError extends ForgeError {
655
+ constructor(route: string, param: string, value: unknown);
170
656
  }
171
657
  /** RF_FE_005:adapter: 'axios' 但未检测到 axios */
172
658
  declare class AdapterNotFoundError extends ForgeError {
@@ -180,8 +666,15 @@ declare class InvalidInterceptorReturnError extends ForgeError {
180
666
  declare class NetworkError extends ForgeError {
181
667
  constructor(message: string, route?: string, level?: string, cause?: unknown);
182
668
  }
183
- /** RF_FE_008:HTTP 非 2xx 且未被 onRejected 拦截器恢复 */
669
+ /**
670
+ * RF_FE_008:HTTP 非 2xx 且未被 onRejected 拦截器恢复。
671
+ *
672
+ * `response` 携带完整的 ResponseData(status/headers/data/config),
673
+ * 供响应拦截器 onRejected 链与最终 catch 逐段检查响应体——典型场景:
674
+ * Laravel 422 校验错误回显(`err.response.data.errors`)。
675
+ */
184
676
  declare class HTTPError extends ForgeError {
677
+ readonly response?: ResponseData;
185
678
  constructor(message: string, opts: {
186
679
  route?: string;
187
680
  level?: string;
@@ -189,11 +682,16 @@ declare class HTTPError extends ForgeError {
189
682
  url?: string;
190
683
  method?: string;
191
684
  cause?: unknown;
685
+ response?: ResponseData;
192
686
  });
193
687
  }
194
688
  /** RF_FE_009:请求被 AbortSignal 取消 */
195
689
  declare class RequestAbortedError extends ForgeError {
196
690
  constructor(route?: string, level?: string, cause?: unknown);
197
691
  }
692
+ /** RF_FE_010:auto-discovery 未完成时调用 route()/hasRoute() 的同步守卫(api() 内部 await discovery,不受此限) */
693
+ declare class DiscoveryNotReadyError extends ForgeError {
694
+ constructor();
695
+ }
198
696
 
199
- export { AdapterNotFoundError, CacheStorage, ForgeError, type ForgeErrorCode, HTTPError, InterceptorHandler, InterceptorManager, InterceptorManagerImpl, InvalidInterceptorReturnError, LevelRoutesResponse, MissingRouteParamError, NetworkError, RequestAbortedError, RouteCache, RouteForge, RouteForgeOptions, RouteMeta, type RouteResolver, UnknownLevelError, UnknownRouteError, createInterceptorManager, createRouteForge, resolveRouteName, resolveRouteNameSync };
697
+ export { AdapterNotFoundError, type AdapterOption, type ApiCallParams, type BoundForge, CacheStorage, DiscoveryNotReadyError, type Fetcher, type ForgeApiParams, type ForgeApiResponse, ForgeError, type ForgeErrorCode, type ForgeRequest, type ForgeRouteMap, type ForgeRouteName, HTTPError, type InterceptorHandler, type InterceptorManager, InterceptorManagerImpl, InvalidInterceptorReturnError, InvalidPathParamError, LevelRoutesResponse, type LoadingChangeCallback, type LoadingChangeEvent, LoadingTracker, MissingRouteParamError, NetworkError, RequestAbortedError, type RequestConfig, type ResponseData, RouteCache, type RouteChangeCallback, RouteChangeTracker, type RouteForge, type RouteForgeOptions, RouteMeta, type RouteResolver, SummaryResponse, UnknownLevelError, UnknownRouteError, type UseForgeApiBoundCall, type UseForgeApiBoundReturn, type UseForgeApiCall, type UseForgeApiReturn, createInterceptorManager, createRouteForge, resolveRouteName, resolveRouteNameSync };