@route-forge/vue 3.0.0 → 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.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var vue = require('vue');
4
3
  var core = require('@route-forge/core');
4
+ var vue = require('vue');
5
5
 
6
6
  // src/plugin.ts
7
7
  var FORGE_INJECTION_KEY = /* @__PURE__ */ Symbol("route-forge");
@@ -128,8 +128,14 @@ function useForgeRouteState(level, name, params, hooks) {
128
128
  });
129
129
  });
130
130
  }
131
+ const dataVersion = vue.ref(0);
132
+ const unsubscribe = forge.onRoutesChange((changed) => {
133
+ if (changed === lvl) dataVersion.value++;
134
+ });
135
+ if (vue.getCurrentScope()) vue.onScopeDispose(unsubscribe);
131
136
  const state = vue.computed(() => {
132
137
  if (!levelLoaded.value) return { href: "", error: null };
138
+ void dataVersion.value;
133
139
  const n = typeof name === "function" ? name() : name;
134
140
  const p = params ? params() : void 0;
135
141
  try {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/plugin.ts","../src/composables/useForgeApi.ts","../src/useInjectedForge.ts","../src/degrade.ts","../src/composables/useForgeRoute.ts","../src/components/shared.ts","../src/components/ForgeRoute.ts","../src/components/ForgeLink.ts","../src/components/ForgeReady.ts"],"names":["createRouteForge","inject","ref","onMounted","computed","watch","getCurrentInstance","defineComponent","h"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Vue 3 插件入口\n * @see .docs/SPEC.md §4.1.7\n *\n * 提供:\n * - 返回对象上的 interceptors(转发实例拦截器):创建后即可同步注册,无需等待 ready()\n * - inject symbol 注入 RouteForge 实例供 composable 使用\n * - useForge() / useForge(level) / useForge(level, prefix) 返回统一方法的 forge 实例\n * • 不传 level:forge(level, name, params?) 直接调用\n * • 传 level:forge(name, params?) 直接调用,自动绑定层级\n * • 传 level + prefix:forge(suffix, params?) 自动拼接 prefix\n *\n * 类型推断:\n * 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,\n * level / name / params 均自动推断,IDE 提供补全提示。\n *\n * 注:v3.0.0 起不再注入 `$forge` 全局属性(残缺 facade,仅 route() 且未 ready 时抛错断渲染);\n * 模板内生成链接用 useForgeRoute / ForgeLink / ForgeRoute,命令式场景用 useForge()。\n */\n\nimport type { App, InjectionKey, Plugin, Ref } from 'vue';\nimport { inject, ref } from 'vue';\nimport {\n type ApiCallParams,\n type BoundForge,\n createRouteForge,\n type RouteForge,\n type RouteForgeOptions,\n} from '@route-forge/core';\n\nexport const FORGE_INJECTION_KEY: InjectionKey<RouteForge> = Symbol('route-forge');\n\nexport interface RouteForgePluginOptions extends RouteForgeOptions {}\n\n/** Vue 特化类型:levelLoaded 为 Ref<boolean> */\nexport type VueBoundForge = BoundForge<Ref<boolean>>;\n\nexport function createRouteForgePlugin(\n forgeOrOptions: RouteForge | RouteForgePluginOptions = {},\n): Plugin<[]> & {\n ready: RouteForge['ready']\n /** 转发实例上的拦截器管理器:创建后即可同步注册,无需等待 ready()(请求/响应拦截链仅影响后续 api() 调用,eager 元信息预加载走 requestRaw 不受影响) */\n interceptors: RouteForge['interceptors']\n} {\n // 复用模式:直接传入 forge 实例(在非组件代码 / SSR 入口持有实例的场景),\n // 忽略 options、不再创建;与 react <RouteForgeProvider forge?> 对称\n const forge = isRouteForge(forgeOrOptions) ? forgeOrOptions : createRouteForge(forgeOrOptions);\n\n return {\n ready: forge.ready.bind(forge),\n interceptors: forge.interceptors,\n install(app: App) {\n app.provide(FORGE_INJECTION_KEY, forge);\n // v3.0.0 起不再注入 $forge 全局属性(残缺 facade 已移除,见 CHANGELOG)\n },\n };\n}\n\n/** 判定入参是否为 forge 实例(而非 options):api + ready 双函数特征 */\nfunction isRouteForge(x: unknown): x is RouteForge {\n return (\n typeof x === 'object' && x !== null &&\n typeof (x as RouteForge).api === 'function' &&\n typeof (x as RouteForge).ready === 'function'\n );\n}\n\n/**\n * 获取 forge 实例。内部委托 core 的 forge.use(),仅将 levelLoaded 替换为 Vue 响应式 Ref。\n *\n * @example\n * // 不绑定层级\n * const forge = useForge()\n * forge('admin', 'users.show', { user: 1 })\n * forge.api('admin', 'users.show')\n *\n * @example\n * // 绑定层级 — 直接调用和 api/route/url 均无需传 level\n * const forge = useForge('admin')\n * forge.level // → 'admin'\n * forge.levelLoaded // Ref<boolean>\n * forge('users.show', { user: 1 })\n * forge.route('users.show', { user: 1 })\n *\n * @example\n * // 绑定层级 + 前缀 — 路由名自动拼接\n * const forge = useForge('admin', 'users')\n * forge('show', { user: 1 }) // → forge.api('admin', 'users.show', ...)\n * forge.route('show', { user: 1 }) // → forge.route('admin', 'users.show', ...)\n */\nexport function useForge<L extends string>(level: L, prefix: string): VueBoundForge;\nexport function useForge<L extends string>(level: L): VueBoundForge;\nexport function useForge(): RouteForge;\nexport function useForge(level?: string, prefix?: string): RouteForge | VueBoundForge {\n const forge = inject(FORGE_INJECTION_KEY);\n if (!forge) {\n throw new Error(\n '[route-forge/vue] useForge() must be used inside an app with createRouteForgePlugin() installed',\n );\n }\n\n if (level === undefined) {\n return forge;\n }\n\n // 委托 core 的 use(),获取 BoundForge(levelLoaded 为 Promise<void>)\n const bound = forge.use(level, prefix);\n\n // 将 levelLoaded 从 Promise<void> 替换为 Ref<boolean>\n const levelLoadedRef = ref(false);\n bound.levelLoaded.then(() => {\n levelLoadedRef.value = true;\n }).catch(() => { /* 加载失败时 levelLoaded 保持 false */ });\n\n Object.defineProperty(bound, 'levelLoaded', {\n value: levelLoadedRef,\n writable: false,\n enumerable: true,\n configurable: true,\n });\n\n return bound as unknown as VueBoundForge;\n}\n","/**\n * useForgeApi:包装 forge.api(),自动管理 loading/error 状态\n * @see .docs/SPEC.md §4.1.7\n *\n * 支持:\n * - useForgeApi() — call(level, name, params)\n * - useForgeApi(level) — call(name, params),自动绑定层级\n * - useForgeApi(level, prefix) — call(suffix, params),自动绑定层级 + 拼接前缀\n *\n * 类型推断:\n * 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,\n * level / name / params 均自动推断,IDE 提供补全提示。\n *\n * pending 采用引用计数:并发多个 call 时,全部完成才置 false\n * (先完成的 call 不再把其他在途请求的 pending 提前清掉)。\n */\n\nimport type { Ref } from 'vue';\nimport { ref } from 'vue';\nimport { useForge } from '../plugin.js';\nimport type {\n BoundForge,\n RouteForge,\n UseForgeApiBoundCall,\n UseForgeApiBoundReturn,\n UseForgeApiCall,\n UseForgeApiReturn,\n} from '@route-forge/core';\n\n// Vue 特化类型:pending/error 为 Ref\nexport type { UseForgeApiCall, UseForgeApiBoundCall };\nexport type UseForgeApiReturnVue = UseForgeApiReturn<Ref<boolean>, Ref<unknown>>;\nexport type UseForgeApiBoundReturnVue<L extends string> = UseForgeApiBoundReturn<L, Ref<boolean>, Ref<unknown>>;\n\n/** 不绑定层级 — call 需要传 level */\nexport function useForgeApi(): UseForgeApiReturnVue;\n/** 绑定层级 — call 无需传 level */\nexport function useForgeApi<L extends string>(level: L): UseForgeApiBoundReturnVue<L>;\n/** 绑定层级 + 前缀 — call 无需传 level,路由名自动拼接 prefix */\nexport function useForgeApi<L extends string>(level: L, prefix: string): UseForgeApiBoundReturnVue<L>;\nexport function useForgeApi(level?: string, prefix?: string): UseForgeApiReturnVue | UseForgeApiBoundReturnVue<string> {\n const bound = level !== undefined ? useForge(level, prefix as string) : undefined;\n const unbound = bound === undefined ? useForge() : undefined;\n const pending = ref(false);\n const error = ref<unknown>(null);\n // 并发计数:setup 闭包变量(组件实例生命周期存活)\n let inflight = 0;\n\n async function call(...args: unknown[]): Promise<{ data: unknown; error: unknown }> {\n inflight++;\n pending.value = true;\n error.value = null;\n try {\n // 按绑定形态分发:bound 走 BoundForge.api(name, params),unbound 走 RouteForge.api(level, name, params)\n // (窄断言替代 as any:重载签名已保证参数形状,此处仅消除联合类型/框架特化类型的分支歧义)\n const data = bound !== undefined\n ? await (bound as unknown as BoundForge).api(args[0] as string, args[1] as never)\n : await (unbound as RouteForge).api(args[0] as string, args[1] as string, args[2] as never);\n return { data, error: null };\n } catch (e) {\n error.value = e;\n return { data: undefined, error: e };\n } finally {\n inflight--;\n pending.value = inflight > 0;\n }\n }\n\n return { pending, error, call: call as unknown as UseForgeApiCall };\n}\n","/**\n * 内部 helper(非公共 API,不进包入口导出):inject forge 实例 + 缺失守卫。\n *\n * useForgeRoute / ForgeRoute / ForgeLink 统一走这里,避免裸 `as RouteForge` 强转:\n * 未安装 plugin 时报「怎么修」的指引性错误,而不是\n * `Cannot read properties of undefined (reading 'isLoaded')` 之类的晦涩堆栈。\n */\n\nimport { inject } from 'vue';\nimport { FORGE_INJECTION_KEY } from './plugin.js';\nimport type { RouteForge } from '@route-forge/core';\n\nexport function useInjectedForge(apiName: string): RouteForge {\n const forge = inject(FORGE_INJECTION_KEY);\n if (!forge) {\n throw new Error(\n `[route-forge/vue] ${apiName} must be used inside an app with createRouteForgePlugin() installed`,\n );\n }\n return forge;\n}\n","/**\n * 降级/渲染警告的统一报告器(内部实现,非公共 API,不进包入口导出):\n * - 会话级去重:同一 (component, message) 或同一渲染错误只报告一次,\n * name/params 联动输入等高频场景不刷屏\n * - enabled=false(createRouteForge({ warnings: false }))时静音\n * - __resetDegradeReportsForTests 仅供测试隔离使用\n */\n\nconst reportedKeys = new Set<string>();\nconst renderWarnKeys = new Set<string>();\n\nfunction dedupeKey(component: string, error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n return `${component}:${message}`;\n}\n\n/** 解析出错降级报告(组件层,error 级) */\nexport function reportDegrade(component: string, error: unknown, enabled = true): void {\n if (!enabled) return;\n const key = dedupeKey(component, error);\n if (reportedKeys.has(key)) return;\n reportedKeys.add(key);\n console.error(\n `%c[route-forge]%c ${component} 路由解析失败(已降级为空字符串,渲染未中断)`,\n 'color:#c0392b;font-weight:bold',\n 'color:inherit',\n error,\n );\n}\n\n/** 渲染期错误降级输出(hook 默认路径,warn 级;组件层通常以 onDegrade 升级为 error) */\nexport function reportRenderWarn(error: unknown, enabled: boolean): void {\n if (!enabled) return;\n const key = `useForgeRoute:${error instanceof Error ? error.message : String(error)}`;\n if (renderWarnKeys.has(key)) return;\n renderWarnKeys.add(key);\n console.warn(\n '%c[route-forge]%c useForgeRoute 渲染期错误(已降级为空字符串,渲染未中断)',\n 'color:#e67e22;font-weight:bold',\n 'color:inherit',\n error,\n );\n}\n\n/** 测试隔离:清空去重状态(不进公共 API) */\nexport function __resetDegradeReportsForTests(): void {\n reportedKeys.clear();\n renderWarnKeys.clear();\n}\n","/**\n * useForgeRoute:响应式 URL 生成器,内部处理 level 加载状态\n * @see .docs/SPEC.md §4.1.7\n *\n * - level 未加载时返回空字符串 ''(不抛错,模板不崩)\n * - level 加载完成后自动重新计算并返回正确 URL\n * - 路由名不存在或必填参数缺失等渲染期错误:降级为 '' 保证渲染不中断,\n * 同时以醒目的样式化 warn 输出完整错误(含堆栈)——开发期可见,生产无副作用\n * - level 为静态字符串(层级是确定性声明,不支持 `() => string` 函数形式):\n * 不支持中途动态切换 level\n * (需要另一个层级请在别的组件 / 别的 useForgeRoute 调用里分别使用,与 useForge 契约一致)\n * - 用户无需关心 levelLoaded 状态,直接用即可\n */\n\nimport { computed, type ComputedRef, onMounted, ref, watch } from 'vue';\nimport { useInjectedForge } from '../useInjectedForge.js';\nimport { reportRenderWarn } from '../degrade.js';\n\n/** 降级报告钩子:组件层(ForgeRoute/ForgeLink)用它把默认 warn 升级为 error,避免双重打印 */\nexport interface ForgeRouteDegradeHooks {\n onDegrade?: (error: unknown) => void;\n}\n\nexport function useForgeRoute(\n level: string,\n name: string | (() => string),\n params?: () => Record<string, unknown> | undefined,\n hooks?: ForgeRouteDegradeHooks,\n): ComputedRef<string> {\n return useForgeRouteState(level, name, params, hooks).href;\n}\n\n/** useForgeRoute 的三态内部形态:组件层(ForgeRoute/ForgeLink)用它区分「未加载 / 解析失败」 */\nexport interface ForgeRouteState {\n /** 生成的 URL;未加载或解析出错时为 '' */\n href: ComputedRef<string>;\n /** 解析错误(仅 level 已加载且 route() 抛错时非 null;未加载恒为 null),响应式 */\n error: ComputedRef<unknown>;\n /** level 是否已加载(区别「未加载」与「已加载但解析失败」两种空串来源),响应式 */\n isLevelLoaded: ComputedRef<boolean>;\n}\n\nexport function useForgeRouteState(\n level: string,\n name: string | (() => string),\n params?: () => Record<string, unknown> | undefined,\n hooks?: ForgeRouteDegradeHooks,\n): ForgeRouteState {\n // 运行时守卫:level 必须是静态字符串(类型收窄后防 JS 用户误用静默降级为空链接)\n if (typeof level !== 'string') {\n throw new TypeError(\n '[route-forge/vue] useForgeRoute(): level must be a static string — ' +\n 'getter form is not supported (levels are deterministic declarations; ' +\n 'create another useForgeRoute call for another level)',\n );\n }\n\n const forge = useInjectedForge('useForgeRoute()');\n\n // level 为静态字符串(层级是确定性声明):绑定即固定,不支持中途动态切换\n //(需要另一个层级请在别的组件 / 别的 useForgeRoute 调用里分别使用,与 useForge 契约一致)。\n // name / params 仍保持响应式。\n const lvl = level;\n\n // 响应式追踪该 level 的加载状态(computed 依赖此 ref 触发重算)\n const levelLoaded = ref(forge.isLoaded(lvl));\n\n if (!levelLoaded.value) {\n onMounted(() => {\n forge.load(lvl).then(() => {\n levelLoaded.value = true;\n }).catch(() => { /* 加载失败时 href 保持 '' */\n });\n });\n }\n\n // 三态同步求值(computed 纯读缓存,无副作用):\n // 未加载 → { href: '', error: null };解析失败 → { href: '', error };成功 → { href }\n const state = computed(() => {\n if (!levelLoaded.value) return { href: '', error: null as unknown };\n const n = typeof name === 'function' ? name() : name;\n const p = params ? params() : undefined;\n try {\n return { href: forge.route(lvl, n, p), error: null as unknown };\n } catch (e) {\n return { href: '', error: e as unknown };\n }\n });\n\n // 降级报告:渲染求值纯净化后,错误经 watch(组件更新前触发)输出,与 react 侧口径一致。\n // 同错会话级去重;createRouteForge({ warnings: false }) 时静音。\n watch(\n () => state.value.error,\n (err) => {\n if (err == null) return;\n if (hooks?.onDegrade) hooks.onDegrade(err);\n else reportRenderWarn(err, forge.warnings);\n },\n { immediate: true },\n );\n\n return {\n href: computed(() => state.value.href),\n error: computed(() => state.value.error),\n isLevelLoaded: computed(() => levelLoaded.value),\n };\n}\n","/**\n * ForgeRoute / ForgeLink 共享内部实现:props 定义、降级报告(转发 degrade.ts)、RouterLink 探测\n * (非公共 API,不进包入口导出)\n */\n\nimport { getCurrentInstance, type PropType } from 'vue';\n\nexport { reportDegrade, reportRenderWarn, __resetDegradeReportsForTests } from '../degrade.js';\n\n/** ForgeRoute / ForgeLink 共享 props:level 静态快照,name / params 双形态响应式 */\n// as const:防止 required: true 被宽化为 boolean,导致 defineComponent 推断出 string | undefined\nexport const forgeLinkProps = {\n /** 层级名:静态快照,setup 求值一次后固定,不支持中途切换 */\n level: { type: String, required: true },\n /** 路由名:string 或 getter 函数,保持响应式 */\n name: {\n type: [String, Function] as PropType<string | (() => string)>,\n required: true,\n },\n /** 路由参数:对象或 getter 函数,保持响应式 */\n params: {\n type: [Object, Function] as PropType<Record<string, unknown> | (() => Record<string, unknown>)>,\n required: false,\n default: undefined,\n },\n /**\n * 手动注入链接组件(组件对象或标签名字符串),注入后同时收到 `href` 与 `to` 两个 prop\n * (对齐 @route-forge/react 的 ForgeLink `as` 契约)。不传时按默认链路:\n * 探测全局 RouterLink → 原生 `<a>`。用于 RouterLink 局部注册 / 非 vue-router 链接组件场景。\n */\n as: {\n type: [Object, String, Function] as PropType<object>,\n required: false,\n default: undefined,\n },\n} as const;\n\n/** level 未加载提示:每实例仅一次(warned 为组件实例内的可变标记),避免正常加载瞬态刷屏 */\nexport function warnUnloadedOnce(component: string, level: string, warned: { value: boolean }): void {\n if (warned.value) return;\n warned.value = true;\n console.warn(\n `[route-forge] ${component}: level \"${level}\" 尚未加载,链接暂不渲染(加载完成后自动出现)`,\n );\n}\n\n/**\n * 从 app 全局组件中探测 vue-router 的 RouterLink(零依赖:不 import vue-router)。\n * vue-router 在 app.use(router) 时会把 RouterLink / router-link 注册到全局组件表;\n * 仅在父组件局部注册 RouterLink 的场景探测不到,此时降级渲染原生 <a>(README 有说明)。\n */\nexport function resolveRouterLink(): object | null {\n const inst = getCurrentInstance();\n const comps = inst?.appContext.components as Record<string, object> | undefined;\n return comps?.RouterLink ?? comps?.['router-link'] ?? null;\n}\n","/**\n * ForgeRoute:URL 生成组件(通用形态),封装 useForgeRoute 的\"先空串、后更新\"异步行为\n * @see .docs/SPEC.md §4.1.7\n *\n * - 通过作用域插槽暴露 { href, loaded },模板里自由决定渲染 <a>、RouterLink 或任意内容\n * - loaded = href !== ''(level 未加载与路由解析出错都降级为 '',正好复用该哨兵值)\n * - 三态分流:未加载 → loading 插槽;已加载但解析失败 → error 插槽(props { error },\n * 未传回落 loading);成功 → default 插槽\n * - 未加载且未传 loading 插槽时默认不渲染;每实例以 console.warn 提醒一次(防刷屏)\n * - 路由解析出错(UnknownRouteError 等)以 console.error 报告,渲染不中断\n * - level 为静态快照,name / params 保持响应式(值或 getter 函数双形态均可)\n */\n\nimport { defineComponent, type SlotsType, type VNode } from 'vue';\nimport { useInjectedForge } from '../useInjectedForge.js';\nimport { useForgeRouteState } from '../composables/useForgeRoute.js';\nimport { forgeLinkProps, reportDegrade, warnUnloadedOnce } from './shared.js';\n\nexport const ForgeRoute = defineComponent({\n name: 'ForgeRoute',\n // 根节点是用户插槽内容,框架透传 attrs 落到插槽上没有意义,显式关闭\n inheritAttrs: false,\n props: forgeLinkProps,\n slots: Object as SlotsType<{\n default?: (props: { href: string; loaded: boolean }) => VNode[];\n loading?: () => VNode[];\n /** 解析失败(路由名不存在等):props 携带错误对象;未传回落 loading 插槽 */\n error?: (props: { error: unknown }) => VNode[];\n }>,\n setup(props, { slots }) {\n const forge = useInjectedForge('ForgeRoute');\n // 统一收敛为 getter:name / params 双形态(值或函数)均保持响应式\n const nameGetter = () => (typeof props.name === 'function' ? props.name() : props.name);\n const paramsGetter = () =>\n typeof props.params === 'function' ? props.params() : props.params;\n const state = useForgeRouteState(props.level, nameGetter, paramsGetter, {\n onDegrade: (e) => reportDegrade('ForgeRoute', e, forge.warnings),\n });\n const unloadWarned = { value: false };\n\n return () => {\n const url = state.href.value;\n const loaded = url !== '';\n if (!loaded && !forge.isLoaded(props.level)) {\n warnUnloadedOnce('ForgeRoute', props.level, unloadWarned);\n }\n // 三态分流:未加载 → loading;解析失败 → error(未传回落 loading)\n if (!state.isLevelLoaded.value) return slots.loading ? slots.loading() : null;\n if (state.error.value != null) {\n return slots.error ? slots.error({ error: state.error.value }) : (slots.loading ? slots.loading() : null);\n }\n return slots.default ? slots.default({ href: url, loaded }) : null;\n };\n },\n});\n\nexport type ForgeRouteProps = InstanceType<typeof ForgeRoute>['$props'];\n","/**\n * ForgeLink:便捷链接组件,封装 useForgeRoute 的\"先空串、后更新\"异步行为\n * @see .docs/SPEC.md §4.1.7\n *\n * - loaded(href !== '')时直接渲染链接:`as` prop 显式注入的组件优先(同时收到 href+to);\n * 否则探测到 vue-router 全局注册的 RouterLink 则渲染 <RouterLink :to=\"href\">(SPA 内部跳转),\n * 再否则渲染原生 <a :href=\"href\">\n * - 三态分流:未加载 → loading 插槽;已加载但解析失败 → error 插槽(props { error },\n * 未传回落 loading);成功 → 链接\n * - 未加载且未传 loading 插槽时默认不渲染;每实例以 console.warn 提醒一次(防刷屏)\n * - 路由解析出错以 console.error 报告,渲染不中断\n * - attrs 透传到根元素(class / target / rel 等),生成的 href / to 优先于同名 attr\n * - level 为静态快照,name / params 保持响应式(值或 getter 函数双形态均可)\n */\n\nimport { defineComponent, h, type SlotsType, type VNode } from 'vue';\nimport { useInjectedForge } from '../useInjectedForge.js';\nimport { useForgeRouteState } from '../composables/useForgeRoute.js';\nimport {\n forgeLinkProps,\n reportDegrade,\n resolveRouterLink,\n warnUnloadedOnce,\n} from './shared.js';\n\nexport const ForgeLink = defineComponent({\n name: 'ForgeLink',\n // attrs 透传到 <a> / RouterLink,但 href / to 必须以组件生成的 URL 为准(显式合并)\n inheritAttrs: false,\n props: forgeLinkProps,\n slots: Object as SlotsType<{\n /** 链接文本/内容 */\n default?: () => VNode[];\n /** 未加载占位 */\n loading?: () => VNode[];\n /** 解析失败(路由名不存在等):props 携带错误对象;未传回落 loading 插槽 */\n error?: (props: { error: unknown }) => VNode[];\n }>,\n setup(props, { slots, attrs }) {\n const forge = useInjectedForge('ForgeLink');\n // 统一收敛为 getter:name / params 双形态(值或函数)均保持响应式\n const nameGetter = () => (typeof props.name === 'function' ? props.name() : props.name);\n const paramsGetter = () =>\n typeof props.params === 'function' ? props.params() : props.params;\n const state = useForgeRouteState(props.level, nameGetter, paramsGetter, {\n onDegrade: (e) => reportDegrade('ForgeLink', e, forge.warnings),\n });\n const unloadWarned = { value: false };\n // 链接组件解析:显式 as prop 优先(同时收 href+to,对齐 react 包契约);\n // 否则探测 RouterLink(app.use(router) 时全局注册,app 生命周期内不变,setup 时探测一次即可)\n const routerLink = resolveRouterLink();\n\n return () => {\n const url = state.href.value;\n const loaded = url !== '';\n if (!loaded && !forge.isLoaded(props.level)) {\n warnUnloadedOnce('ForgeLink', props.level, unloadWarned);\n }\n // 三态分流:未加载 → loading;解析失败 → error(未传回落 loading)\n if (!state.isLevelLoaded.value) return slots.loading ? slots.loading() : null;\n if (state.error.value != null) {\n return slots.error ? slots.error({ error: state.error.value }) : (slots.loading ? slots.loading() : null);\n }\n\n const children = slots.default ? slots.default() : undefined;\n if (props.as) {\n // 手动注入的链接组件:同时收到 href 与 to(对齐 @route-forge/react 的 as 契约)\n return h(\n props.as as object,\n { ...(attrs as Record<string, unknown>), to: url, href: url },\n { default: () => children },\n );\n }\n if (routerLink) {\n return h(\n routerLink,\n { ...(attrs as Record<string, unknown>), to: url },\n { default: () => children },\n );\n }\n return h('a', { ...(attrs as Record<string, unknown>), href: url }, children);\n };\n },\n});\n\nexport type ForgeLinkProps = InstanceType<typeof ForgeLink>['$props'];\n","/**\n * ForgeReady:ready 门闩组件——直接 mount 也能拿到 `ready().then(mount)` 同级的确定性。\n *\n * - ready() 未 resolve 时渲染 `fallback` 插槽(缺省不渲染任何内容),resolve 后渲染 default 插槽\n * - forge 已就绪(core `isReady()`)时同步开门,不产生多余的 fallback 首帧\n * - ready() reject:响亮 `console.error` 且保持闭门(与 `ready().then(mount).catch` 的语义对齐,\n * 不静默)——需要 reject 后继续渲染请勿使用本组件,改用 `ready().then(mount, onRejected)`\n *\n * @example\n * ```vue\n * <ForgeReady>\n * <template #fallback><Splash /></template>\n * <RouterView />\n * </ForgeReady>\n * ```\n */\n\nimport { defineComponent, ref, type SlotsType, type VNode } from 'vue';\nimport { useInjectedForge } from '../useInjectedForge.js';\n\nexport const ForgeReady = defineComponent({\n name: 'ForgeReady',\n slots: Object as SlotsType<{\n /** ready 后渲染的内容 */\n default?: () => VNode[];\n /** 门闩期间的占位 UI(缺省不渲染任何内容) */\n fallback?: () => VNode[];\n }>,\n setup(_, { slots }) {\n const forge = useInjectedForge('ForgeReady');\n const open = ref(forge.isReady());\n if (!open.value) {\n forge.ready().then(\n () => {\n open.value = true;\n },\n (err) => {\n console.error(\n '[route-forge] ForgeReady: ready() rejected — content stays gated (same as an unhandled ready().catch)',\n err,\n );\n },\n );\n }\n return () => (open.value ? slots.default?.() : (slots.fallback ? slots.fallback() : null));\n },\n});\n\nexport type ForgeReadyProps = InstanceType<typeof ForgeReady>['$props'];\n"]}
1
+ {"version":3,"sources":["../src/plugin.ts","../src/composables/useForge.ts","../src/composables/useForgeApi.ts","../src/useInjectedForge.ts","../src/degrade.ts","../src/composables/useForgeRoute.ts","../src/components/shared.ts","../src/components/ForgeRoute.ts","../src/components/ForgeLink.ts","../src/components/ForgeReady.ts"],"names":["createRouteForge","inject","ref","onMounted","getCurrentScope","onScopeDispose","computed","watch","getCurrentInstance","defineComponent","h"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Vue 3 插件入口\n * @see .docs/SPEC.md §4.1.7\n *\n * 提供:\n * - createRouteForgePlugin:装配插件,install 时经 inject symbol 注入 RouteForge 实例\n * - 返回对象上的 interceptors(转发实例拦截器):创建后即可同步注册,无需等待 ready()\n *\n * useForge / useForgeApi / useForgeRoute 等消费 composable 见 composables/ 下各文件。\n *\n * 注:v3.0.0 起不再注入 `$forge` 全局属性(残缺 facade,仅 route() 且未 ready 时抛错断渲染);\n * 模板内生成链接用 useForgeRoute / ForgeLink / ForgeRoute,命令式场景用 useForge()。\n */\n\nimport type { App, InjectionKey, Plugin } from 'vue';\nimport {\n createRouteForge,\n type RouteForge,\n type RouteForgeOptions,\n} from '@route-forge/core';\n\nexport const FORGE_INJECTION_KEY: InjectionKey<RouteForge> = Symbol('route-forge');\n\nexport interface RouteForgePluginOptions extends RouteForgeOptions {}\n\nexport function createRouteForgePlugin(\n forgeOrOptions: RouteForge | RouteForgePluginOptions = {},\n): Plugin<[]> & {\n ready: RouteForge['ready']\n /** 转发实例上的拦截器管理器:创建后即可同步注册,无需等待 ready()(请求/响应拦截链仅影响后续 api() 调用,eager 元信息预加载走 requestRaw 不受影响) */\n interceptors: RouteForge['interceptors']\n} {\n // 复用模式:直接传入 forge 实例(在非组件代码 / SSR 入口持有实例的场景),\n // 忽略 options、不再创建;与 react <RouteForgeProvider forge?> 对称\n const forge = isRouteForge(forgeOrOptions) ? forgeOrOptions : createRouteForge(forgeOrOptions);\n\n return {\n ready: forge.ready.bind(forge),\n interceptors: forge.interceptors,\n install(app: App) {\n app.provide(FORGE_INJECTION_KEY, forge);\n // v3.0.0 起不再注入 $forge 全局属性(残缺 facade 已移除,见 CHANGELOG)\n },\n };\n}\n\n/** 判定入参是否为 forge 实例(而非 options):api + ready 双函数特征 */\nfunction isRouteForge(x: unknown): x is RouteForge {\n return (\n typeof x === 'object' && x !== null &&\n typeof (x as RouteForge).api === 'function' &&\n typeof (x as RouteForge).ready === 'function'\n );\n}\n","/**\n * useForge — 获取 forge 实例(Vue 特化:levelLoaded 为 Ref<boolean>)\n * @see .docs/SPEC.md §4.1.7\n *\n * 内部委托 core 的 forge.use(),仅将 levelLoaded 从 Promise<void> 替换为 Vue 响应式 Ref。\n *\n * @example\n * // 不绑定层级\n * const forge = useForge()\n * forge('admin', 'users.show', { user: 1 })\n * forge.api('admin', 'users.show')\n *\n * @example\n * // 绑定层级 — 直接调用和 api/route/url 均无需传 level\n * const forge = useForge('admin')\n * forge.level // → 'admin'\n * forge.levelLoaded // Ref<boolean>\n * forge('users.show', { user: 1 })\n * forge.route('users.show', { user: 1 })\n *\n * @example\n * // 绑定层级 + 前缀 — 路由名自动拼接\n * const forge = useForge('admin', 'users')\n * forge('show', { user: 1 }) // → forge.api('admin', 'users.show', ...)\n * forge.route('show', { user: 1 }) // → forge.route('admin', 'users.show', ...)\n */\n\nimport { inject, ref, type Ref } from 'vue';\nimport { type BoundForge, type RouteForge } from '@route-forge/core';\nimport { FORGE_INJECTION_KEY } from '../plugin.js';\n\n/** Vue 特化类型:levelLoaded 为 Ref<boolean> */\nexport type VueBoundForge = BoundForge<Ref<boolean>>;\n\nexport function useForge<L extends string>(level: L, prefix: string): VueBoundForge;\nexport function useForge<L extends string>(level: L): VueBoundForge;\nexport function useForge(): RouteForge;\nexport function useForge(level?: string, prefix?: string): RouteForge | VueBoundForge {\n const forge = inject(FORGE_INJECTION_KEY);\n if (!forge) {\n throw new Error(\n '[route-forge/vue] useForge() must be used inside an app with createRouteForgePlugin() installed',\n );\n }\n\n if (level === undefined) {\n return forge;\n }\n\n // 委托 core 的 use(),获取 BoundForge(levelLoaded 为 Promise<void>)\n const bound = forge.use(level, prefix);\n\n // 将 levelLoaded 从 Promise<void> 替换为 Ref<boolean>\n const levelLoadedRef = ref(false);\n bound.levelLoaded.then(() => {\n levelLoadedRef.value = true;\n }).catch(() => { /* 加载失败时 levelLoaded 保持 false */ });\n\n Object.defineProperty(bound, 'levelLoaded', {\n value: levelLoadedRef,\n writable: false,\n enumerable: true,\n configurable: true,\n });\n\n return bound as unknown as VueBoundForge;\n}\n","/**\n * useForgeApi:包装 forge.api(),自动管理 loading/error 状态\n * @see .docs/SPEC.md §4.1.7\n *\n * 支持:\n * - useForgeApi() — call(level, name, params)\n * - useForgeApi(level) — call(name, params),自动绑定层级\n * - useForgeApi(level, prefix) — call(suffix, params),自动绑定层级 + 拼接前缀\n *\n * 类型推断:\n * 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,\n * level / name / params 均自动推断,IDE 提供补全提示。\n *\n * pending 采用引用计数:并发多个 call 时,全部完成才置 false\n * (先完成的 call 不再把其他在途请求的 pending 提前清掉)。\n */\n\nimport type { Ref } from 'vue';\nimport { ref } from 'vue';\nimport { useForge } from './useForge.js';\nimport type {\n BoundForge,\n RouteForge,\n UseForgeApiBoundCall,\n UseForgeApiBoundReturn,\n UseForgeApiCall,\n UseForgeApiReturn,\n} from '@route-forge/core';\n\n// Vue 特化类型:pending/error 为 Ref\nexport type { UseForgeApiCall, UseForgeApiBoundCall };\nexport type UseForgeApiReturnVue = UseForgeApiReturn<Ref<boolean>, Ref<unknown>>;\nexport type UseForgeApiBoundReturnVue<L extends string> = UseForgeApiBoundReturn<L, Ref<boolean>, Ref<unknown>>;\n\n/** 不绑定层级 — call 需要传 level */\nexport function useForgeApi(): UseForgeApiReturnVue;\n/** 绑定层级 — call 无需传 level */\nexport function useForgeApi<L extends string>(level: L): UseForgeApiBoundReturnVue<L>;\n/** 绑定层级 + 前缀 — call 无需传 level,路由名自动拼接 prefix */\nexport function useForgeApi<L extends string>(level: L, prefix: string): UseForgeApiBoundReturnVue<L>;\nexport function useForgeApi(level?: string, prefix?: string): UseForgeApiReturnVue | UseForgeApiBoundReturnVue<string> {\n const bound = level !== undefined ? useForge(level, prefix as string) : undefined;\n const unbound = bound === undefined ? useForge() : undefined;\n const pending = ref(false);\n const error = ref<unknown>(null);\n // 并发计数:setup 闭包变量(组件实例生命周期存活)\n let inflight = 0;\n\n async function call(...args: unknown[]): Promise<{ data: unknown; error: unknown }> {\n inflight++;\n pending.value = true;\n error.value = null;\n try {\n // 按绑定形态分发:bound 走 BoundForge.api(name, params),unbound 走 RouteForge.api(level, name, params)\n // (窄断言替代 as any:重载签名已保证参数形状,此处仅消除联合类型/框架特化类型的分支歧义)\n const data = bound !== undefined\n ? await (bound as unknown as BoundForge).api(args[0] as string, args[1] as never)\n : await (unbound as RouteForge).api(args[0] as string, args[1] as string, args[2] as never);\n return { data, error: null };\n } catch (e) {\n error.value = e;\n return { data: undefined, error: e };\n } finally {\n inflight--;\n pending.value = inflight > 0;\n }\n }\n\n return { pending, error, call: call as unknown as UseForgeApiCall };\n}\n","/**\n * 内部 helper(非公共 API,不进包入口导出):inject forge 实例 + 缺失守卫。\n *\n * useForgeRoute / ForgeRoute / ForgeLink 统一走这里,避免裸 `as RouteForge` 强转:\n * 未安装 plugin 时报「怎么修」的指引性错误,而不是\n * `Cannot read properties of undefined (reading 'isLoaded')` 之类的晦涩堆栈。\n */\n\nimport { inject } from 'vue';\nimport { FORGE_INJECTION_KEY } from './plugin.js';\nimport type { RouteForge } from '@route-forge/core';\n\nexport function useInjectedForge(apiName: string): RouteForge {\n const forge = inject(FORGE_INJECTION_KEY);\n if (!forge) {\n throw new Error(\n `[route-forge/vue] ${apiName} must be used inside an app with createRouteForgePlugin() installed`,\n );\n }\n return forge;\n}\n","/**\n * 降级/渲染警告的统一报告器(内部实现,非公共 API,不进包入口导出):\n * - 会话级去重:同一 (component, message) 或同一渲染错误只报告一次,\n * name/params 联动输入等高频场景不刷屏\n * - enabled=false(createRouteForge({ warnings: false }))时静音\n * - __resetDegradeReportsForTests 仅供测试隔离使用\n */\n\nconst reportedKeys = new Set<string>();\nconst renderWarnKeys = new Set<string>();\n\nfunction dedupeKey(component: string, error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n return `${component}:${message}`;\n}\n\n/** 解析出错降级报告(组件层,error 级) */\nexport function reportDegrade(component: string, error: unknown, enabled = true): void {\n if (!enabled) return;\n const key = dedupeKey(component, error);\n if (reportedKeys.has(key)) return;\n reportedKeys.add(key);\n console.error(\n `%c[route-forge]%c ${component} 路由解析失败(已降级为空字符串,渲染未中断)`,\n 'color:#c0392b;font-weight:bold',\n 'color:inherit',\n error,\n );\n}\n\n/** 渲染期错误降级输出(hook 默认路径,warn 级;组件层通常以 onDegrade 升级为 error) */\nexport function reportRenderWarn(error: unknown, enabled: boolean): void {\n if (!enabled) return;\n const key = `useForgeRoute:${error instanceof Error ? error.message : String(error)}`;\n if (renderWarnKeys.has(key)) return;\n renderWarnKeys.add(key);\n console.warn(\n '%c[route-forge]%c useForgeRoute 渲染期错误(已降级为空字符串,渲染未中断)',\n 'color:#e67e22;font-weight:bold',\n 'color:inherit',\n error,\n );\n}\n\n/** 测试隔离:清空去重状态(不进公共 API) */\nexport function __resetDegradeReportsForTests(): void {\n reportedKeys.clear();\n renderWarnKeys.clear();\n}\n","/**\n * useForgeRoute:响应式 URL 生成器,内部处理 level 加载状态\n * @see .docs/SPEC.md §4.1.7\n *\n * - level 未加载时返回空字符串 ''(不抛错,模板不崩)\n * - level 加载完成后自动重新计算并返回正确 URL\n * - 路由名不存在或必填参数缺失等渲染期错误:降级为 '' 保证渲染不中断,\n * 同时以醒目的样式化 warn 输出完整错误(含堆栈)——开发期可见,生产无副作用\n * - level 为静态字符串(层级是确定性声明,不支持 `() => string` 函数形式):\n * 不支持中途动态切换 level\n * (需要另一个层级请在别的组件 / 别的 useForgeRoute 调用里分别使用,与 useForge 契约一致)\n * - 用户无需关心 levelLoaded 状态,直接用即可\n */\n\nimport { computed, type ComputedRef, getCurrentScope, onMounted, onScopeDispose, ref, watch } from 'vue';\nimport { useInjectedForge } from '../useInjectedForge.js';\nimport { reportRenderWarn } from '../degrade.js';\n\n/** 降级报告钩子:组件层(ForgeRoute/ForgeLink)用它把默认 warn 升级为 error,避免双重打印 */\nexport interface ForgeRouteDegradeHooks {\n onDegrade?: (error: unknown) => void;\n}\n\nexport function useForgeRoute(\n level: string,\n name: string | (() => string),\n params?: () => Record<string, unknown> | undefined,\n hooks?: ForgeRouteDegradeHooks,\n): ComputedRef<string> {\n return useForgeRouteState(level, name, params, hooks).href;\n}\n\n/** useForgeRoute 的三态内部形态:组件层(ForgeRoute/ForgeLink)用它区分「未加载 / 解析失败」 */\nexport interface ForgeRouteState {\n /** 生成的 URL;未加载或解析出错时为 '' */\n href: ComputedRef<string>;\n /** 解析错误(仅 level 已加载且 route() 抛错时非 null;未加载恒为 null),响应式 */\n error: ComputedRef<unknown>;\n /** level 是否已加载(区别「未加载」与「已加载但解析失败」两种空串来源),响应式 */\n isLevelLoaded: ComputedRef<boolean>;\n}\n\nexport function useForgeRouteState(\n level: string,\n name: string | (() => string),\n params?: () => Record<string, unknown> | undefined,\n hooks?: ForgeRouteDegradeHooks,\n): ForgeRouteState {\n // 运行时守卫:level 必须是静态字符串(类型收窄后防 JS 用户误用静默降级为空链接)\n if (typeof level !== 'string') {\n throw new TypeError(\n '[route-forge/vue] useForgeRoute(): level must be a static string — ' +\n 'getter form is not supported (levels are deterministic declarations; ' +\n 'create another useForgeRoute call for another level)',\n );\n }\n\n const forge = useInjectedForge('useForgeRoute()');\n\n // level 为静态字符串(层级是确定性声明):绑定即固定,不支持中途动态切换\n //(需要另一个层级请在别的组件 / 别的 useForgeRoute 调用里分别使用,与 useForge 契约一致)。\n // name / params 仍保持响应式。\n const lvl = level;\n\n // 响应式追踪该 level 的加载状态(computed 依赖此 ref 触发重算)\n const levelLoaded = ref(forge.isLoaded(lvl));\n\n if (!levelLoaded.value) {\n onMounted(() => {\n forge.load(lvl).then(() => {\n levelLoaded.value = true;\n }).catch(() => { /* 加载失败时 href 保持 '' */\n });\n });\n }\n\n // 路由数据版本:本层级被 revalidate 刷新 / invalidate 后 bump,驱动下面的 computed 重算(无刷新页面即热更新)\n const dataVersion = ref(0);\n const unsubscribe = forge.onRoutesChange((changed) => {\n if (changed === lvl) dataVersion.value++;\n });\n // 在 effect scope 内则随 scope 销毁自动退订;scope 外(如单例模块)不注册、由调用方持有 unsubscribe 自行管理\n if (getCurrentScope()) onScopeDispose(unsubscribe);\n\n // 三态同步求值(computed 纯读缓存,无副作用):\n // 未加载 → { href: '', error: null };解析失败 → { href: '', error };成功 → { href }\n const state = computed(() => {\n if (!levelLoaded.value) return { href: '', error: null as unknown };\n void dataVersion.value; // 依赖数据版本:revalidate/invalidate 后强制重算\n const n = typeof name === 'function' ? name() : name;\n const p = params ? params() : undefined;\n try {\n return { href: forge.route(lvl, n, p), error: null as unknown };\n } catch (e) {\n return { href: '', error: e as unknown };\n }\n });\n\n // 降级报告:渲染求值纯净化后,错误经 watch(组件更新前触发)输出,与 react 侧口径一致。\n // 同错会话级去重;createRouteForge({ warnings: false }) 时静音。\n watch(\n () => state.value.error,\n (err) => {\n if (err == null) return;\n if (hooks?.onDegrade) hooks.onDegrade(err);\n else reportRenderWarn(err, forge.warnings);\n },\n { immediate: true },\n );\n\n return {\n href: computed(() => state.value.href),\n error: computed(() => state.value.error),\n isLevelLoaded: computed(() => levelLoaded.value),\n };\n}\n","/**\n * ForgeRoute / ForgeLink 共享内部实现:props 定义、降级报告(转发 degrade.ts)、RouterLink 探测\n * (非公共 API,不进包入口导出)\n */\n\nimport { getCurrentInstance, type PropType } from 'vue';\n\nexport { reportDegrade, reportRenderWarn, __resetDegradeReportsForTests } from '../degrade.js';\n\n/** ForgeRoute / ForgeLink 共享 props:level 静态快照,name / params 双形态响应式 */\n// as const:防止 required: true 被宽化为 boolean,导致 defineComponent 推断出 string | undefined\nexport const forgeLinkProps = {\n /** 层级名:静态快照,setup 求值一次后固定,不支持中途切换 */\n level: { type: String, required: true },\n /** 路由名:string 或 getter 函数,保持响应式 */\n name: {\n type: [String, Function] as PropType<string | (() => string)>,\n required: true,\n },\n /** 路由参数:对象或 getter 函数,保持响应式 */\n params: {\n type: [Object, Function] as PropType<Record<string, unknown> | (() => Record<string, unknown>)>,\n required: false,\n default: undefined,\n },\n /**\n * 手动注入链接组件(组件对象或标签名字符串),注入后同时收到 `href` 与 `to` 两个 prop\n * (对齐 @route-forge/react 的 ForgeLink `as` 契约)。不传时按默认链路:\n * 探测全局 RouterLink → 原生 `<a>`。用于 RouterLink 局部注册 / 非 vue-router 链接组件场景。\n */\n as: {\n type: [Object, String, Function] as PropType<object>,\n required: false,\n default: undefined,\n },\n} as const;\n\n/** level 未加载提示:每实例仅一次(warned 为组件实例内的可变标记),避免正常加载瞬态刷屏 */\nexport function warnUnloadedOnce(component: string, level: string, warned: { value: boolean }): void {\n if (warned.value) return;\n warned.value = true;\n console.warn(\n `[route-forge] ${component}: level \"${level}\" 尚未加载,链接暂不渲染(加载完成后自动出现)`,\n );\n}\n\n/**\n * 从 app 全局组件中探测 vue-router 的 RouterLink(零依赖:不 import vue-router)。\n * vue-router 在 app.use(router) 时会把 RouterLink / router-link 注册到全局组件表;\n * 仅在父组件局部注册 RouterLink 的场景探测不到,此时降级渲染原生 <a>(README 有说明)。\n */\nexport function resolveRouterLink(): object | null {\n const inst = getCurrentInstance();\n const comps = inst?.appContext.components as Record<string, object> | undefined;\n return comps?.RouterLink ?? comps?.['router-link'] ?? null;\n}\n","/**\n * ForgeRoute:URL 生成组件(通用形态),封装 useForgeRoute 的\"先空串、后更新\"异步行为\n * @see .docs/SPEC.md §4.1.7\n *\n * - 通过作用域插槽暴露 { href, loaded },模板里自由决定渲染 <a>、RouterLink 或任意内容\n * - loaded = href !== ''(level 未加载与路由解析出错都降级为 '',正好复用该哨兵值)\n * - 三态分流:未加载 → loading 插槽;已加载但解析失败 → error 插槽(props { error },\n * 未传回落 loading);成功 → default 插槽\n * - 未加载且未传 loading 插槽时默认不渲染;每实例以 console.warn 提醒一次(防刷屏)\n * - 路由解析出错(UnknownRouteError 等)以 console.error 报告,渲染不中断\n * - level 为静态快照,name / params 保持响应式(值或 getter 函数双形态均可)\n */\n\nimport { defineComponent, type SlotsType, type VNode } from 'vue';\nimport { useInjectedForge } from '../useInjectedForge.js';\nimport { useForgeRouteState } from '../composables/useForgeRoute.js';\nimport { forgeLinkProps, reportDegrade, warnUnloadedOnce } from './shared.js';\n\nexport const ForgeRoute = defineComponent({\n name: 'ForgeRoute',\n // 根节点是用户插槽内容,框架透传 attrs 落到插槽上没有意义,显式关闭\n inheritAttrs: false,\n props: forgeLinkProps,\n slots: Object as SlotsType<{\n default?: (props: { href: string; loaded: boolean }) => VNode[];\n loading?: () => VNode[];\n /** 解析失败(路由名不存在等):props 携带错误对象;未传回落 loading 插槽 */\n error?: (props: { error: unknown }) => VNode[];\n }>,\n setup(props, { slots }) {\n const forge = useInjectedForge('ForgeRoute');\n // 统一收敛为 getter:name / params 双形态(值或函数)均保持响应式\n const nameGetter = () => (typeof props.name === 'function' ? props.name() : props.name);\n const paramsGetter = () =>\n typeof props.params === 'function' ? props.params() : props.params;\n const state = useForgeRouteState(props.level, nameGetter, paramsGetter, {\n onDegrade: (e) => reportDegrade('ForgeRoute', e, forge.warnings),\n });\n const unloadWarned = { value: false };\n\n return () => {\n const url = state.href.value;\n const loaded = url !== '';\n if (!loaded && !forge.isLoaded(props.level)) {\n warnUnloadedOnce('ForgeRoute', props.level, unloadWarned);\n }\n // 三态分流:未加载 → loading;解析失败 → error(未传回落 loading)\n if (!state.isLevelLoaded.value) return slots.loading ? slots.loading() : null;\n if (state.error.value != null) {\n return slots.error ? slots.error({ error: state.error.value }) : (slots.loading ? slots.loading() : null);\n }\n return slots.default ? slots.default({ href: url, loaded }) : null;\n };\n },\n});\n\nexport type ForgeRouteProps = InstanceType<typeof ForgeRoute>['$props'];\n","/**\n * ForgeLink:便捷链接组件,封装 useForgeRoute 的\"先空串、后更新\"异步行为\n * @see .docs/SPEC.md §4.1.7\n *\n * - loaded(href !== '')时直接渲染链接:`as` prop 显式注入的组件优先(同时收到 href+to);\n * 否则探测到 vue-router 全局注册的 RouterLink 则渲染 <RouterLink :to=\"href\">(SPA 内部跳转),\n * 再否则渲染原生 <a :href=\"href\">\n * - 三态分流:未加载 → loading 插槽;已加载但解析失败 → error 插槽(props { error },\n * 未传回落 loading);成功 → 链接\n * - 未加载且未传 loading 插槽时默认不渲染;每实例以 console.warn 提醒一次(防刷屏)\n * - 路由解析出错以 console.error 报告,渲染不中断\n * - attrs 透传到根元素(class / target / rel 等),生成的 href / to 优先于同名 attr\n * - level 为静态快照,name / params 保持响应式(值或 getter 函数双形态均可)\n */\n\nimport { defineComponent, h, type SlotsType, type VNode } from 'vue';\nimport { useInjectedForge } from '../useInjectedForge.js';\nimport { useForgeRouteState } from '../composables/useForgeRoute.js';\nimport {\n forgeLinkProps,\n reportDegrade,\n resolveRouterLink,\n warnUnloadedOnce,\n} from './shared.js';\n\nexport const ForgeLink = defineComponent({\n name: 'ForgeLink',\n // attrs 透传到 <a> / RouterLink,但 href / to 必须以组件生成的 URL 为准(显式合并)\n inheritAttrs: false,\n props: forgeLinkProps,\n slots: Object as SlotsType<{\n /** 链接文本/内容 */\n default?: () => VNode[];\n /** 未加载占位 */\n loading?: () => VNode[];\n /** 解析失败(路由名不存在等):props 携带错误对象;未传回落 loading 插槽 */\n error?: (props: { error: unknown }) => VNode[];\n }>,\n setup(props, { slots, attrs }) {\n const forge = useInjectedForge('ForgeLink');\n // 统一收敛为 getter:name / params 双形态(值或函数)均保持响应式\n const nameGetter = () => (typeof props.name === 'function' ? props.name() : props.name);\n const paramsGetter = () =>\n typeof props.params === 'function' ? props.params() : props.params;\n const state = useForgeRouteState(props.level, nameGetter, paramsGetter, {\n onDegrade: (e) => reportDegrade('ForgeLink', e, forge.warnings),\n });\n const unloadWarned = { value: false };\n // 链接组件解析:显式 as prop 优先(同时收 href+to,对齐 react 包契约);\n // 否则探测 RouterLink(app.use(router) 时全局注册,app 生命周期内不变,setup 时探测一次即可)\n const routerLink = resolveRouterLink();\n\n return () => {\n const url = state.href.value;\n const loaded = url !== '';\n if (!loaded && !forge.isLoaded(props.level)) {\n warnUnloadedOnce('ForgeLink', props.level, unloadWarned);\n }\n // 三态分流:未加载 → loading;解析失败 → error(未传回落 loading)\n if (!state.isLevelLoaded.value) return slots.loading ? slots.loading() : null;\n if (state.error.value != null) {\n return slots.error ? slots.error({ error: state.error.value }) : (slots.loading ? slots.loading() : null);\n }\n\n const children = slots.default ? slots.default() : undefined;\n if (props.as) {\n // 手动注入的链接组件:同时收到 href 与 to(对齐 @route-forge/react 的 as 契约)\n return h(\n props.as as object,\n { ...(attrs as Record<string, unknown>), to: url, href: url },\n { default: () => children },\n );\n }\n if (routerLink) {\n return h(\n routerLink,\n { ...(attrs as Record<string, unknown>), to: url },\n { default: () => children },\n );\n }\n return h('a', { ...(attrs as Record<string, unknown>), href: url }, children);\n };\n },\n});\n\nexport type ForgeLinkProps = InstanceType<typeof ForgeLink>['$props'];\n","/**\n * ForgeReady:ready 门闩组件——直接 mount 也能拿到 `ready().then(mount)` 同级的确定性。\n *\n * - ready() 未 resolve 时渲染 `fallback` 插槽(缺省不渲染任何内容),resolve 后渲染 default 插槽\n * - forge 已就绪(core `isReady()`)时同步开门,不产生多余的 fallback 首帧\n * - ready() reject:响亮 `console.error` 且保持闭门(与 `ready().then(mount).catch` 的语义对齐,\n * 不静默)——需要 reject 后继续渲染请勿使用本组件,改用 `ready().then(mount, onRejected)`\n *\n * @example\n * ```vue\n * <ForgeReady>\n * <template #fallback><Splash /></template>\n * <RouterView />\n * </ForgeReady>\n * ```\n */\n\nimport { defineComponent, ref, type SlotsType, type VNode } from 'vue';\nimport { useInjectedForge } from '../useInjectedForge.js';\n\nexport const ForgeReady = defineComponent({\n name: 'ForgeReady',\n slots: Object as SlotsType<{\n /** ready 后渲染的内容 */\n default?: () => VNode[];\n /** 门闩期间的占位 UI(缺省不渲染任何内容) */\n fallback?: () => VNode[];\n }>,\n setup(_, { slots }) {\n const forge = useInjectedForge('ForgeReady');\n const open = ref(forge.isReady());\n if (!open.value) {\n forge.ready().then(\n () => {\n open.value = true;\n },\n (err) => {\n console.error(\n '[route-forge] ForgeReady: ready() rejected — content stays gated (same as an unhandled ready().catch)',\n err,\n );\n },\n );\n }\n return () => (open.value ? slots.default?.() : (slots.fallback ? slots.fallback() : null));\n },\n});\n\nexport type ForgeReadyProps = InstanceType<typeof ForgeReady>['$props'];\n"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as vue from 'vue';
2
- import { InjectionKey, Ref, Plugin, ComputedRef, VNode, SlotsType } from 'vue';
2
+ import { InjectionKey, Plugin, Ref, ComputedRef, VNode, SlotsType } from 'vue';
3
3
  import { RouteForge, RouteForgeOptions, BoundForge, UseForgeApiBoundReturn, UseForgeApiReturn } from '@route-forge/core';
4
4
  export { UseForgeApiBoundCall, UseForgeApiCall } from '@route-forge/core';
5
5
 
@@ -8,16 +8,10 @@ export { UseForgeApiBoundCall, UseForgeApiCall } from '@route-forge/core';
8
8
  * @see .docs/SPEC.md §4.1.7
9
9
  *
10
10
  * 提供:
11
+ * - createRouteForgePlugin:装配插件,install 时经 inject symbol 注入 RouteForge 实例
11
12
  * - 返回对象上的 interceptors(转发实例拦截器):创建后即可同步注册,无需等待 ready()
12
- * - inject symbol 注入 RouteForge 实例供 composable 使用
13
- * - useForge() / useForge(level) / useForge(level, prefix) 返回统一方法的 forge 实例
14
- * • 不传 level:forge(level, name, params?) 直接调用
15
- * • 传 level:forge(name, params?) 直接调用,自动绑定层级
16
- * • 传 level + prefix:forge(suffix, params?) 自动拼接 prefix
17
13
  *
18
- * 类型推断:
19
- * 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,
20
- * level / name / params 均自动推断,IDE 提供补全提示。
14
+ * useForge / useForgeApi / useForgeRoute 等消费 composable 见 composables/ 下各文件。
21
15
  *
22
16
  * 注:v3.0.0 起不再注入 `$forge` 全局属性(残缺 facade,仅 route() 且未 ready 时抛错断渲染);
23
17
  * 模板内生成链接用 useForgeRoute / ForgeLink / ForgeRoute,命令式场景用 useForge()。
@@ -26,15 +20,17 @@ export { UseForgeApiBoundCall, UseForgeApiCall } from '@route-forge/core';
26
20
  declare const FORGE_INJECTION_KEY: InjectionKey<RouteForge>;
27
21
  interface RouteForgePluginOptions extends RouteForgeOptions {
28
22
  }
29
- /** Vue 特化类型:levelLoaded 为 Ref<boolean> */
30
- type VueBoundForge = BoundForge<Ref<boolean>>;
31
23
  declare function createRouteForgePlugin(forgeOrOptions?: RouteForge | RouteForgePluginOptions): Plugin<[]> & {
32
24
  ready: RouteForge['ready'];
33
25
  /** 转发实例上的拦截器管理器:创建后即可同步注册,无需等待 ready()(请求/响应拦截链仅影响后续 api() 调用,eager 元信息预加载走 requestRaw 不受影响) */
34
26
  interceptors: RouteForge['interceptors'];
35
27
  };
28
+
36
29
  /**
37
- * 获取 forge 实例。内部委托 core 的 forge.use(),仅将 levelLoaded 替换为 Vue 响应式 Ref
30
+ * useForge — 获取 forge 实例(Vue 特化:levelLoaded Ref<boolean>)
31
+ * @see .docs/SPEC.md §4.1.7
32
+ *
33
+ * 内部委托 core 的 forge.use(),仅将 levelLoaded 从 Promise<void> 替换为 Vue 响应式 Ref。
38
34
  *
39
35
  * @example
40
36
  * // 不绑定层级
@@ -56,6 +52,9 @@ declare function createRouteForgePlugin(forgeOrOptions?: RouteForge | RouteForge
56
52
  * forge('show', { user: 1 }) // → forge.api('admin', 'users.show', ...)
57
53
  * forge.route('show', { user: 1 }) // → forge.route('admin', 'users.show', ...)
58
54
  */
55
+
56
+ /** Vue 特化类型:levelLoaded 为 Ref<boolean> */
57
+ type VueBoundForge = BoundForge<Ref<boolean>>;
59
58
  declare function useForge<L extends string>(level: L, prefix: string): VueBoundForge;
60
59
  declare function useForge<L extends string>(level: L): VueBoundForge;
61
60
  declare function useForge(): RouteForge;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as vue from 'vue';
2
- import { InjectionKey, Ref, Plugin, ComputedRef, VNode, SlotsType } from 'vue';
2
+ import { InjectionKey, Plugin, Ref, ComputedRef, VNode, SlotsType } from 'vue';
3
3
  import { RouteForge, RouteForgeOptions, BoundForge, UseForgeApiBoundReturn, UseForgeApiReturn } from '@route-forge/core';
4
4
  export { UseForgeApiBoundCall, UseForgeApiCall } from '@route-forge/core';
5
5
 
@@ -8,16 +8,10 @@ export { UseForgeApiBoundCall, UseForgeApiCall } from '@route-forge/core';
8
8
  * @see .docs/SPEC.md §4.1.7
9
9
  *
10
10
  * 提供:
11
+ * - createRouteForgePlugin:装配插件,install 时经 inject symbol 注入 RouteForge 实例
11
12
  * - 返回对象上的 interceptors(转发实例拦截器):创建后即可同步注册,无需等待 ready()
12
- * - inject symbol 注入 RouteForge 实例供 composable 使用
13
- * - useForge() / useForge(level) / useForge(level, prefix) 返回统一方法的 forge 实例
14
- * • 不传 level:forge(level, name, params?) 直接调用
15
- * • 传 level:forge(name, params?) 直接调用,自动绑定层级
16
- * • 传 level + prefix:forge(suffix, params?) 自动拼接 prefix
17
13
  *
18
- * 类型推断:
19
- * 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,
20
- * level / name / params 均自动推断,IDE 提供补全提示。
14
+ * useForge / useForgeApi / useForgeRoute 等消费 composable 见 composables/ 下各文件。
21
15
  *
22
16
  * 注:v3.0.0 起不再注入 `$forge` 全局属性(残缺 facade,仅 route() 且未 ready 时抛错断渲染);
23
17
  * 模板内生成链接用 useForgeRoute / ForgeLink / ForgeRoute,命令式场景用 useForge()。
@@ -26,15 +20,17 @@ export { UseForgeApiBoundCall, UseForgeApiCall } from '@route-forge/core';
26
20
  declare const FORGE_INJECTION_KEY: InjectionKey<RouteForge>;
27
21
  interface RouteForgePluginOptions extends RouteForgeOptions {
28
22
  }
29
- /** Vue 特化类型:levelLoaded 为 Ref<boolean> */
30
- type VueBoundForge = BoundForge<Ref<boolean>>;
31
23
  declare function createRouteForgePlugin(forgeOrOptions?: RouteForge | RouteForgePluginOptions): Plugin<[]> & {
32
24
  ready: RouteForge['ready'];
33
25
  /** 转发实例上的拦截器管理器:创建后即可同步注册,无需等待 ready()(请求/响应拦截链仅影响后续 api() 调用,eager 元信息预加载走 requestRaw 不受影响) */
34
26
  interceptors: RouteForge['interceptors'];
35
27
  };
28
+
36
29
  /**
37
- * 获取 forge 实例。内部委托 core 的 forge.use(),仅将 levelLoaded 替换为 Vue 响应式 Ref
30
+ * useForge — 获取 forge 实例(Vue 特化:levelLoaded Ref<boolean>)
31
+ * @see .docs/SPEC.md §4.1.7
32
+ *
33
+ * 内部委托 core 的 forge.use(),仅将 levelLoaded 从 Promise<void> 替换为 Vue 响应式 Ref。
38
34
  *
39
35
  * @example
40
36
  * // 不绑定层级
@@ -56,6 +52,9 @@ declare function createRouteForgePlugin(forgeOrOptions?: RouteForge | RouteForge
56
52
  * forge('show', { user: 1 }) // → forge.api('admin', 'users.show', ...)
57
53
  * forge.route('show', { user: 1 }) // → forge.route('admin', 'users.show', ...)
58
54
  */
55
+
56
+ /** Vue 特化类型:levelLoaded 为 Ref<boolean> */
57
+ type VueBoundForge = BoundForge<Ref<boolean>>;
59
58
  declare function useForge<L extends string>(level: L, prefix: string): VueBoundForge;
60
59
  declare function useForge<L extends string>(level: L): VueBoundForge;
61
60
  declare function useForge(): RouteForge;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { defineComponent, h, ref, inject, onMounted, computed, watch, getCurrentInstance } from 'vue';
2
1
  import { createRouteForge } from '@route-forge/core';
2
+ import { defineComponent, h, ref, inject, onMounted, getCurrentScope, onScopeDispose, computed, watch, getCurrentInstance } from 'vue';
3
3
 
4
4
  // src/plugin.ts
5
5
  var FORGE_INJECTION_KEY = /* @__PURE__ */ Symbol("route-forge");
@@ -126,8 +126,14 @@ function useForgeRouteState(level, name, params, hooks) {
126
126
  });
127
127
  });
128
128
  }
129
+ const dataVersion = ref(0);
130
+ const unsubscribe = forge.onRoutesChange((changed) => {
131
+ if (changed === lvl) dataVersion.value++;
132
+ });
133
+ if (getCurrentScope()) onScopeDispose(unsubscribe);
129
134
  const state = computed(() => {
130
135
  if (!levelLoaded.value) return { href: "", error: null };
136
+ void dataVersion.value;
131
137
  const n = typeof name === "function" ? name() : name;
132
138
  const p = params ? params() : void 0;
133
139
  try {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/plugin.ts","../src/composables/useForgeApi.ts","../src/useInjectedForge.ts","../src/degrade.ts","../src/composables/useForgeRoute.ts","../src/components/shared.ts","../src/components/ForgeRoute.ts","../src/components/ForgeLink.ts","../src/components/ForgeReady.ts"],"names":["ref","inject","defineComponent"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Vue 3 插件入口\n * @see .docs/SPEC.md §4.1.7\n *\n * 提供:\n * - 返回对象上的 interceptors(转发实例拦截器):创建后即可同步注册,无需等待 ready()\n * - inject symbol 注入 RouteForge 实例供 composable 使用\n * - useForge() / useForge(level) / useForge(level, prefix) 返回统一方法的 forge 实例\n * • 不传 level:forge(level, name, params?) 直接调用\n * • 传 level:forge(name, params?) 直接调用,自动绑定层级\n * • 传 level + prefix:forge(suffix, params?) 自动拼接 prefix\n *\n * 类型推断:\n * 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,\n * level / name / params 均自动推断,IDE 提供补全提示。\n *\n * 注:v3.0.0 起不再注入 `$forge` 全局属性(残缺 facade,仅 route() 且未 ready 时抛错断渲染);\n * 模板内生成链接用 useForgeRoute / ForgeLink / ForgeRoute,命令式场景用 useForge()。\n */\n\nimport type { App, InjectionKey, Plugin, Ref } from 'vue';\nimport { inject, ref } from 'vue';\nimport {\n type ApiCallParams,\n type BoundForge,\n createRouteForge,\n type RouteForge,\n type RouteForgeOptions,\n} from '@route-forge/core';\n\nexport const FORGE_INJECTION_KEY: InjectionKey<RouteForge> = Symbol('route-forge');\n\nexport interface RouteForgePluginOptions extends RouteForgeOptions {}\n\n/** Vue 特化类型:levelLoaded 为 Ref<boolean> */\nexport type VueBoundForge = BoundForge<Ref<boolean>>;\n\nexport function createRouteForgePlugin(\n forgeOrOptions: RouteForge | RouteForgePluginOptions = {},\n): Plugin<[]> & {\n ready: RouteForge['ready']\n /** 转发实例上的拦截器管理器:创建后即可同步注册,无需等待 ready()(请求/响应拦截链仅影响后续 api() 调用,eager 元信息预加载走 requestRaw 不受影响) */\n interceptors: RouteForge['interceptors']\n} {\n // 复用模式:直接传入 forge 实例(在非组件代码 / SSR 入口持有实例的场景),\n // 忽略 options、不再创建;与 react <RouteForgeProvider forge?> 对称\n const forge = isRouteForge(forgeOrOptions) ? forgeOrOptions : createRouteForge(forgeOrOptions);\n\n return {\n ready: forge.ready.bind(forge),\n interceptors: forge.interceptors,\n install(app: App) {\n app.provide(FORGE_INJECTION_KEY, forge);\n // v3.0.0 起不再注入 $forge 全局属性(残缺 facade 已移除,见 CHANGELOG)\n },\n };\n}\n\n/** 判定入参是否为 forge 实例(而非 options):api + ready 双函数特征 */\nfunction isRouteForge(x: unknown): x is RouteForge {\n return (\n typeof x === 'object' && x !== null &&\n typeof (x as RouteForge).api === 'function' &&\n typeof (x as RouteForge).ready === 'function'\n );\n}\n\n/**\n * 获取 forge 实例。内部委托 core 的 forge.use(),仅将 levelLoaded 替换为 Vue 响应式 Ref。\n *\n * @example\n * // 不绑定层级\n * const forge = useForge()\n * forge('admin', 'users.show', { user: 1 })\n * forge.api('admin', 'users.show')\n *\n * @example\n * // 绑定层级 — 直接调用和 api/route/url 均无需传 level\n * const forge = useForge('admin')\n * forge.level // → 'admin'\n * forge.levelLoaded // Ref<boolean>\n * forge('users.show', { user: 1 })\n * forge.route('users.show', { user: 1 })\n *\n * @example\n * // 绑定层级 + 前缀 — 路由名自动拼接\n * const forge = useForge('admin', 'users')\n * forge('show', { user: 1 }) // → forge.api('admin', 'users.show', ...)\n * forge.route('show', { user: 1 }) // → forge.route('admin', 'users.show', ...)\n */\nexport function useForge<L extends string>(level: L, prefix: string): VueBoundForge;\nexport function useForge<L extends string>(level: L): VueBoundForge;\nexport function useForge(): RouteForge;\nexport function useForge(level?: string, prefix?: string): RouteForge | VueBoundForge {\n const forge = inject(FORGE_INJECTION_KEY);\n if (!forge) {\n throw new Error(\n '[route-forge/vue] useForge() must be used inside an app with createRouteForgePlugin() installed',\n );\n }\n\n if (level === undefined) {\n return forge;\n }\n\n // 委托 core 的 use(),获取 BoundForge(levelLoaded 为 Promise<void>)\n const bound = forge.use(level, prefix);\n\n // 将 levelLoaded 从 Promise<void> 替换为 Ref<boolean>\n const levelLoadedRef = ref(false);\n bound.levelLoaded.then(() => {\n levelLoadedRef.value = true;\n }).catch(() => { /* 加载失败时 levelLoaded 保持 false */ });\n\n Object.defineProperty(bound, 'levelLoaded', {\n value: levelLoadedRef,\n writable: false,\n enumerable: true,\n configurable: true,\n });\n\n return bound as unknown as VueBoundForge;\n}\n","/**\n * useForgeApi:包装 forge.api(),自动管理 loading/error 状态\n * @see .docs/SPEC.md §4.1.7\n *\n * 支持:\n * - useForgeApi() — call(level, name, params)\n * - useForgeApi(level) — call(name, params),自动绑定层级\n * - useForgeApi(level, prefix) — call(suffix, params),自动绑定层级 + 拼接前缀\n *\n * 类型推断:\n * 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,\n * level / name / params 均自动推断,IDE 提供补全提示。\n *\n * pending 采用引用计数:并发多个 call 时,全部完成才置 false\n * (先完成的 call 不再把其他在途请求的 pending 提前清掉)。\n */\n\nimport type { Ref } from 'vue';\nimport { ref } from 'vue';\nimport { useForge } from '../plugin.js';\nimport type {\n BoundForge,\n RouteForge,\n UseForgeApiBoundCall,\n UseForgeApiBoundReturn,\n UseForgeApiCall,\n UseForgeApiReturn,\n} from '@route-forge/core';\n\n// Vue 特化类型:pending/error 为 Ref\nexport type { UseForgeApiCall, UseForgeApiBoundCall };\nexport type UseForgeApiReturnVue = UseForgeApiReturn<Ref<boolean>, Ref<unknown>>;\nexport type UseForgeApiBoundReturnVue<L extends string> = UseForgeApiBoundReturn<L, Ref<boolean>, Ref<unknown>>;\n\n/** 不绑定层级 — call 需要传 level */\nexport function useForgeApi(): UseForgeApiReturnVue;\n/** 绑定层级 — call 无需传 level */\nexport function useForgeApi<L extends string>(level: L): UseForgeApiBoundReturnVue<L>;\n/** 绑定层级 + 前缀 — call 无需传 level,路由名自动拼接 prefix */\nexport function useForgeApi<L extends string>(level: L, prefix: string): UseForgeApiBoundReturnVue<L>;\nexport function useForgeApi(level?: string, prefix?: string): UseForgeApiReturnVue | UseForgeApiBoundReturnVue<string> {\n const bound = level !== undefined ? useForge(level, prefix as string) : undefined;\n const unbound = bound === undefined ? useForge() : undefined;\n const pending = ref(false);\n const error = ref<unknown>(null);\n // 并发计数:setup 闭包变量(组件实例生命周期存活)\n let inflight = 0;\n\n async function call(...args: unknown[]): Promise<{ data: unknown; error: unknown }> {\n inflight++;\n pending.value = true;\n error.value = null;\n try {\n // 按绑定形态分发:bound 走 BoundForge.api(name, params),unbound 走 RouteForge.api(level, name, params)\n // (窄断言替代 as any:重载签名已保证参数形状,此处仅消除联合类型/框架特化类型的分支歧义)\n const data = bound !== undefined\n ? await (bound as unknown as BoundForge).api(args[0] as string, args[1] as never)\n : await (unbound as RouteForge).api(args[0] as string, args[1] as string, args[2] as never);\n return { data, error: null };\n } catch (e) {\n error.value = e;\n return { data: undefined, error: e };\n } finally {\n inflight--;\n pending.value = inflight > 0;\n }\n }\n\n return { pending, error, call: call as unknown as UseForgeApiCall };\n}\n","/**\n * 内部 helper(非公共 API,不进包入口导出):inject forge 实例 + 缺失守卫。\n *\n * useForgeRoute / ForgeRoute / ForgeLink 统一走这里,避免裸 `as RouteForge` 强转:\n * 未安装 plugin 时报「怎么修」的指引性错误,而不是\n * `Cannot read properties of undefined (reading 'isLoaded')` 之类的晦涩堆栈。\n */\n\nimport { inject } from 'vue';\nimport { FORGE_INJECTION_KEY } from './plugin.js';\nimport type { RouteForge } from '@route-forge/core';\n\nexport function useInjectedForge(apiName: string): RouteForge {\n const forge = inject(FORGE_INJECTION_KEY);\n if (!forge) {\n throw new Error(\n `[route-forge/vue] ${apiName} must be used inside an app with createRouteForgePlugin() installed`,\n );\n }\n return forge;\n}\n","/**\n * 降级/渲染警告的统一报告器(内部实现,非公共 API,不进包入口导出):\n * - 会话级去重:同一 (component, message) 或同一渲染错误只报告一次,\n * name/params 联动输入等高频场景不刷屏\n * - enabled=false(createRouteForge({ warnings: false }))时静音\n * - __resetDegradeReportsForTests 仅供测试隔离使用\n */\n\nconst reportedKeys = new Set<string>();\nconst renderWarnKeys = new Set<string>();\n\nfunction dedupeKey(component: string, error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n return `${component}:${message}`;\n}\n\n/** 解析出错降级报告(组件层,error 级) */\nexport function reportDegrade(component: string, error: unknown, enabled = true): void {\n if (!enabled) return;\n const key = dedupeKey(component, error);\n if (reportedKeys.has(key)) return;\n reportedKeys.add(key);\n console.error(\n `%c[route-forge]%c ${component} 路由解析失败(已降级为空字符串,渲染未中断)`,\n 'color:#c0392b;font-weight:bold',\n 'color:inherit',\n error,\n );\n}\n\n/** 渲染期错误降级输出(hook 默认路径,warn 级;组件层通常以 onDegrade 升级为 error) */\nexport function reportRenderWarn(error: unknown, enabled: boolean): void {\n if (!enabled) return;\n const key = `useForgeRoute:${error instanceof Error ? error.message : String(error)}`;\n if (renderWarnKeys.has(key)) return;\n renderWarnKeys.add(key);\n console.warn(\n '%c[route-forge]%c useForgeRoute 渲染期错误(已降级为空字符串,渲染未中断)',\n 'color:#e67e22;font-weight:bold',\n 'color:inherit',\n error,\n );\n}\n\n/** 测试隔离:清空去重状态(不进公共 API) */\nexport function __resetDegradeReportsForTests(): void {\n reportedKeys.clear();\n renderWarnKeys.clear();\n}\n","/**\n * useForgeRoute:响应式 URL 生成器,内部处理 level 加载状态\n * @see .docs/SPEC.md §4.1.7\n *\n * - level 未加载时返回空字符串 ''(不抛错,模板不崩)\n * - level 加载完成后自动重新计算并返回正确 URL\n * - 路由名不存在或必填参数缺失等渲染期错误:降级为 '' 保证渲染不中断,\n * 同时以醒目的样式化 warn 输出完整错误(含堆栈)——开发期可见,生产无副作用\n * - level 为静态字符串(层级是确定性声明,不支持 `() => string` 函数形式):\n * 不支持中途动态切换 level\n * (需要另一个层级请在别的组件 / 别的 useForgeRoute 调用里分别使用,与 useForge 契约一致)\n * - 用户无需关心 levelLoaded 状态,直接用即可\n */\n\nimport { computed, type ComputedRef, onMounted, ref, watch } from 'vue';\nimport { useInjectedForge } from '../useInjectedForge.js';\nimport { reportRenderWarn } from '../degrade.js';\n\n/** 降级报告钩子:组件层(ForgeRoute/ForgeLink)用它把默认 warn 升级为 error,避免双重打印 */\nexport interface ForgeRouteDegradeHooks {\n onDegrade?: (error: unknown) => void;\n}\n\nexport function useForgeRoute(\n level: string,\n name: string | (() => string),\n params?: () => Record<string, unknown> | undefined,\n hooks?: ForgeRouteDegradeHooks,\n): ComputedRef<string> {\n return useForgeRouteState(level, name, params, hooks).href;\n}\n\n/** useForgeRoute 的三态内部形态:组件层(ForgeRoute/ForgeLink)用它区分「未加载 / 解析失败」 */\nexport interface ForgeRouteState {\n /** 生成的 URL;未加载或解析出错时为 '' */\n href: ComputedRef<string>;\n /** 解析错误(仅 level 已加载且 route() 抛错时非 null;未加载恒为 null),响应式 */\n error: ComputedRef<unknown>;\n /** level 是否已加载(区别「未加载」与「已加载但解析失败」两种空串来源),响应式 */\n isLevelLoaded: ComputedRef<boolean>;\n}\n\nexport function useForgeRouteState(\n level: string,\n name: string | (() => string),\n params?: () => Record<string, unknown> | undefined,\n hooks?: ForgeRouteDegradeHooks,\n): ForgeRouteState {\n // 运行时守卫:level 必须是静态字符串(类型收窄后防 JS 用户误用静默降级为空链接)\n if (typeof level !== 'string') {\n throw new TypeError(\n '[route-forge/vue] useForgeRoute(): level must be a static string — ' +\n 'getter form is not supported (levels are deterministic declarations; ' +\n 'create another useForgeRoute call for another level)',\n );\n }\n\n const forge = useInjectedForge('useForgeRoute()');\n\n // level 为静态字符串(层级是确定性声明):绑定即固定,不支持中途动态切换\n //(需要另一个层级请在别的组件 / 别的 useForgeRoute 调用里分别使用,与 useForge 契约一致)。\n // name / params 仍保持响应式。\n const lvl = level;\n\n // 响应式追踪该 level 的加载状态(computed 依赖此 ref 触发重算)\n const levelLoaded = ref(forge.isLoaded(lvl));\n\n if (!levelLoaded.value) {\n onMounted(() => {\n forge.load(lvl).then(() => {\n levelLoaded.value = true;\n }).catch(() => { /* 加载失败时 href 保持 '' */\n });\n });\n }\n\n // 三态同步求值(computed 纯读缓存,无副作用):\n // 未加载 → { href: '', error: null };解析失败 → { href: '', error };成功 → { href }\n const state = computed(() => {\n if (!levelLoaded.value) return { href: '', error: null as unknown };\n const n = typeof name === 'function' ? name() : name;\n const p = params ? params() : undefined;\n try {\n return { href: forge.route(lvl, n, p), error: null as unknown };\n } catch (e) {\n return { href: '', error: e as unknown };\n }\n });\n\n // 降级报告:渲染求值纯净化后,错误经 watch(组件更新前触发)输出,与 react 侧口径一致。\n // 同错会话级去重;createRouteForge({ warnings: false }) 时静音。\n watch(\n () => state.value.error,\n (err) => {\n if (err == null) return;\n if (hooks?.onDegrade) hooks.onDegrade(err);\n else reportRenderWarn(err, forge.warnings);\n },\n { immediate: true },\n );\n\n return {\n href: computed(() => state.value.href),\n error: computed(() => state.value.error),\n isLevelLoaded: computed(() => levelLoaded.value),\n };\n}\n","/**\n * ForgeRoute / ForgeLink 共享内部实现:props 定义、降级报告(转发 degrade.ts)、RouterLink 探测\n * (非公共 API,不进包入口导出)\n */\n\nimport { getCurrentInstance, type PropType } from 'vue';\n\nexport { reportDegrade, reportRenderWarn, __resetDegradeReportsForTests } from '../degrade.js';\n\n/** ForgeRoute / ForgeLink 共享 props:level 静态快照,name / params 双形态响应式 */\n// as const:防止 required: true 被宽化为 boolean,导致 defineComponent 推断出 string | undefined\nexport const forgeLinkProps = {\n /** 层级名:静态快照,setup 求值一次后固定,不支持中途切换 */\n level: { type: String, required: true },\n /** 路由名:string 或 getter 函数,保持响应式 */\n name: {\n type: [String, Function] as PropType<string | (() => string)>,\n required: true,\n },\n /** 路由参数:对象或 getter 函数,保持响应式 */\n params: {\n type: [Object, Function] as PropType<Record<string, unknown> | (() => Record<string, unknown>)>,\n required: false,\n default: undefined,\n },\n /**\n * 手动注入链接组件(组件对象或标签名字符串),注入后同时收到 `href` 与 `to` 两个 prop\n * (对齐 @route-forge/react 的 ForgeLink `as` 契约)。不传时按默认链路:\n * 探测全局 RouterLink → 原生 `<a>`。用于 RouterLink 局部注册 / 非 vue-router 链接组件场景。\n */\n as: {\n type: [Object, String, Function] as PropType<object>,\n required: false,\n default: undefined,\n },\n} as const;\n\n/** level 未加载提示:每实例仅一次(warned 为组件实例内的可变标记),避免正常加载瞬态刷屏 */\nexport function warnUnloadedOnce(component: string, level: string, warned: { value: boolean }): void {\n if (warned.value) return;\n warned.value = true;\n console.warn(\n `[route-forge] ${component}: level \"${level}\" 尚未加载,链接暂不渲染(加载完成后自动出现)`,\n );\n}\n\n/**\n * 从 app 全局组件中探测 vue-router 的 RouterLink(零依赖:不 import vue-router)。\n * vue-router 在 app.use(router) 时会把 RouterLink / router-link 注册到全局组件表;\n * 仅在父组件局部注册 RouterLink 的场景探测不到,此时降级渲染原生 <a>(README 有说明)。\n */\nexport function resolveRouterLink(): object | null {\n const inst = getCurrentInstance();\n const comps = inst?.appContext.components as Record<string, object> | undefined;\n return comps?.RouterLink ?? comps?.['router-link'] ?? null;\n}\n","/**\n * ForgeRoute:URL 生成组件(通用形态),封装 useForgeRoute 的\"先空串、后更新\"异步行为\n * @see .docs/SPEC.md §4.1.7\n *\n * - 通过作用域插槽暴露 { href, loaded },模板里自由决定渲染 <a>、RouterLink 或任意内容\n * - loaded = href !== ''(level 未加载与路由解析出错都降级为 '',正好复用该哨兵值)\n * - 三态分流:未加载 → loading 插槽;已加载但解析失败 → error 插槽(props { error },\n * 未传回落 loading);成功 → default 插槽\n * - 未加载且未传 loading 插槽时默认不渲染;每实例以 console.warn 提醒一次(防刷屏)\n * - 路由解析出错(UnknownRouteError 等)以 console.error 报告,渲染不中断\n * - level 为静态快照,name / params 保持响应式(值或 getter 函数双形态均可)\n */\n\nimport { defineComponent, type SlotsType, type VNode } from 'vue';\nimport { useInjectedForge } from '../useInjectedForge.js';\nimport { useForgeRouteState } from '../composables/useForgeRoute.js';\nimport { forgeLinkProps, reportDegrade, warnUnloadedOnce } from './shared.js';\n\nexport const ForgeRoute = defineComponent({\n name: 'ForgeRoute',\n // 根节点是用户插槽内容,框架透传 attrs 落到插槽上没有意义,显式关闭\n inheritAttrs: false,\n props: forgeLinkProps,\n slots: Object as SlotsType<{\n default?: (props: { href: string; loaded: boolean }) => VNode[];\n loading?: () => VNode[];\n /** 解析失败(路由名不存在等):props 携带错误对象;未传回落 loading 插槽 */\n error?: (props: { error: unknown }) => VNode[];\n }>,\n setup(props, { slots }) {\n const forge = useInjectedForge('ForgeRoute');\n // 统一收敛为 getter:name / params 双形态(值或函数)均保持响应式\n const nameGetter = () => (typeof props.name === 'function' ? props.name() : props.name);\n const paramsGetter = () =>\n typeof props.params === 'function' ? props.params() : props.params;\n const state = useForgeRouteState(props.level, nameGetter, paramsGetter, {\n onDegrade: (e) => reportDegrade('ForgeRoute', e, forge.warnings),\n });\n const unloadWarned = { value: false };\n\n return () => {\n const url = state.href.value;\n const loaded = url !== '';\n if (!loaded && !forge.isLoaded(props.level)) {\n warnUnloadedOnce('ForgeRoute', props.level, unloadWarned);\n }\n // 三态分流:未加载 → loading;解析失败 → error(未传回落 loading)\n if (!state.isLevelLoaded.value) return slots.loading ? slots.loading() : null;\n if (state.error.value != null) {\n return slots.error ? slots.error({ error: state.error.value }) : (slots.loading ? slots.loading() : null);\n }\n return slots.default ? slots.default({ href: url, loaded }) : null;\n };\n },\n});\n\nexport type ForgeRouteProps = InstanceType<typeof ForgeRoute>['$props'];\n","/**\n * ForgeLink:便捷链接组件,封装 useForgeRoute 的\"先空串、后更新\"异步行为\n * @see .docs/SPEC.md §4.1.7\n *\n * - loaded(href !== '')时直接渲染链接:`as` prop 显式注入的组件优先(同时收到 href+to);\n * 否则探测到 vue-router 全局注册的 RouterLink 则渲染 <RouterLink :to=\"href\">(SPA 内部跳转),\n * 再否则渲染原生 <a :href=\"href\">\n * - 三态分流:未加载 → loading 插槽;已加载但解析失败 → error 插槽(props { error },\n * 未传回落 loading);成功 → 链接\n * - 未加载且未传 loading 插槽时默认不渲染;每实例以 console.warn 提醒一次(防刷屏)\n * - 路由解析出错以 console.error 报告,渲染不中断\n * - attrs 透传到根元素(class / target / rel 等),生成的 href / to 优先于同名 attr\n * - level 为静态快照,name / params 保持响应式(值或 getter 函数双形态均可)\n */\n\nimport { defineComponent, h, type SlotsType, type VNode } from 'vue';\nimport { useInjectedForge } from '../useInjectedForge.js';\nimport { useForgeRouteState } from '../composables/useForgeRoute.js';\nimport {\n forgeLinkProps,\n reportDegrade,\n resolveRouterLink,\n warnUnloadedOnce,\n} from './shared.js';\n\nexport const ForgeLink = defineComponent({\n name: 'ForgeLink',\n // attrs 透传到 <a> / RouterLink,但 href / to 必须以组件生成的 URL 为准(显式合并)\n inheritAttrs: false,\n props: forgeLinkProps,\n slots: Object as SlotsType<{\n /** 链接文本/内容 */\n default?: () => VNode[];\n /** 未加载占位 */\n loading?: () => VNode[];\n /** 解析失败(路由名不存在等):props 携带错误对象;未传回落 loading 插槽 */\n error?: (props: { error: unknown }) => VNode[];\n }>,\n setup(props, { slots, attrs }) {\n const forge = useInjectedForge('ForgeLink');\n // 统一收敛为 getter:name / params 双形态(值或函数)均保持响应式\n const nameGetter = () => (typeof props.name === 'function' ? props.name() : props.name);\n const paramsGetter = () =>\n typeof props.params === 'function' ? props.params() : props.params;\n const state = useForgeRouteState(props.level, nameGetter, paramsGetter, {\n onDegrade: (e) => reportDegrade('ForgeLink', e, forge.warnings),\n });\n const unloadWarned = { value: false };\n // 链接组件解析:显式 as prop 优先(同时收 href+to,对齐 react 包契约);\n // 否则探测 RouterLink(app.use(router) 时全局注册,app 生命周期内不变,setup 时探测一次即可)\n const routerLink = resolveRouterLink();\n\n return () => {\n const url = state.href.value;\n const loaded = url !== '';\n if (!loaded && !forge.isLoaded(props.level)) {\n warnUnloadedOnce('ForgeLink', props.level, unloadWarned);\n }\n // 三态分流:未加载 → loading;解析失败 → error(未传回落 loading)\n if (!state.isLevelLoaded.value) return slots.loading ? slots.loading() : null;\n if (state.error.value != null) {\n return slots.error ? slots.error({ error: state.error.value }) : (slots.loading ? slots.loading() : null);\n }\n\n const children = slots.default ? slots.default() : undefined;\n if (props.as) {\n // 手动注入的链接组件:同时收到 href 与 to(对齐 @route-forge/react 的 as 契约)\n return h(\n props.as as object,\n { ...(attrs as Record<string, unknown>), to: url, href: url },\n { default: () => children },\n );\n }\n if (routerLink) {\n return h(\n routerLink,\n { ...(attrs as Record<string, unknown>), to: url },\n { default: () => children },\n );\n }\n return h('a', { ...(attrs as Record<string, unknown>), href: url }, children);\n };\n },\n});\n\nexport type ForgeLinkProps = InstanceType<typeof ForgeLink>['$props'];\n","/**\n * ForgeReady:ready 门闩组件——直接 mount 也能拿到 `ready().then(mount)` 同级的确定性。\n *\n * - ready() 未 resolve 时渲染 `fallback` 插槽(缺省不渲染任何内容),resolve 后渲染 default 插槽\n * - forge 已就绪(core `isReady()`)时同步开门,不产生多余的 fallback 首帧\n * - ready() reject:响亮 `console.error` 且保持闭门(与 `ready().then(mount).catch` 的语义对齐,\n * 不静默)——需要 reject 后继续渲染请勿使用本组件,改用 `ready().then(mount, onRejected)`\n *\n * @example\n * ```vue\n * <ForgeReady>\n * <template #fallback><Splash /></template>\n * <RouterView />\n * </ForgeReady>\n * ```\n */\n\nimport { defineComponent, ref, type SlotsType, type VNode } from 'vue';\nimport { useInjectedForge } from '../useInjectedForge.js';\n\nexport const ForgeReady = defineComponent({\n name: 'ForgeReady',\n slots: Object as SlotsType<{\n /** ready 后渲染的内容 */\n default?: () => VNode[];\n /** 门闩期间的占位 UI(缺省不渲染任何内容) */\n fallback?: () => VNode[];\n }>,\n setup(_, { slots }) {\n const forge = useInjectedForge('ForgeReady');\n const open = ref(forge.isReady());\n if (!open.value) {\n forge.ready().then(\n () => {\n open.value = true;\n },\n (err) => {\n console.error(\n '[route-forge] ForgeReady: ready() rejected — content stays gated (same as an unhandled ready().catch)',\n err,\n );\n },\n );\n }\n return () => (open.value ? slots.default?.() : (slots.fallback ? slots.fallback() : null));\n },\n});\n\nexport type ForgeReadyProps = InstanceType<typeof ForgeReady>['$props'];\n"]}
1
+ {"version":3,"sources":["../src/plugin.ts","../src/composables/useForge.ts","../src/composables/useForgeApi.ts","../src/useInjectedForge.ts","../src/degrade.ts","../src/composables/useForgeRoute.ts","../src/components/shared.ts","../src/components/ForgeRoute.ts","../src/components/ForgeLink.ts","../src/components/ForgeReady.ts"],"names":["ref","inject","defineComponent"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Vue 3 插件入口\n * @see .docs/SPEC.md §4.1.7\n *\n * 提供:\n * - createRouteForgePlugin:装配插件,install 时经 inject symbol 注入 RouteForge 实例\n * - 返回对象上的 interceptors(转发实例拦截器):创建后即可同步注册,无需等待 ready()\n *\n * useForge / useForgeApi / useForgeRoute 等消费 composable 见 composables/ 下各文件。\n *\n * 注:v3.0.0 起不再注入 `$forge` 全局属性(残缺 facade,仅 route() 且未 ready 时抛错断渲染);\n * 模板内生成链接用 useForgeRoute / ForgeLink / ForgeRoute,命令式场景用 useForge()。\n */\n\nimport type { App, InjectionKey, Plugin } from 'vue';\nimport {\n createRouteForge,\n type RouteForge,\n type RouteForgeOptions,\n} from '@route-forge/core';\n\nexport const FORGE_INJECTION_KEY: InjectionKey<RouteForge> = Symbol('route-forge');\n\nexport interface RouteForgePluginOptions extends RouteForgeOptions {}\n\nexport function createRouteForgePlugin(\n forgeOrOptions: RouteForge | RouteForgePluginOptions = {},\n): Plugin<[]> & {\n ready: RouteForge['ready']\n /** 转发实例上的拦截器管理器:创建后即可同步注册,无需等待 ready()(请求/响应拦截链仅影响后续 api() 调用,eager 元信息预加载走 requestRaw 不受影响) */\n interceptors: RouteForge['interceptors']\n} {\n // 复用模式:直接传入 forge 实例(在非组件代码 / SSR 入口持有实例的场景),\n // 忽略 options、不再创建;与 react <RouteForgeProvider forge?> 对称\n const forge = isRouteForge(forgeOrOptions) ? forgeOrOptions : createRouteForge(forgeOrOptions);\n\n return {\n ready: forge.ready.bind(forge),\n interceptors: forge.interceptors,\n install(app: App) {\n app.provide(FORGE_INJECTION_KEY, forge);\n // v3.0.0 起不再注入 $forge 全局属性(残缺 facade 已移除,见 CHANGELOG)\n },\n };\n}\n\n/** 判定入参是否为 forge 实例(而非 options):api + ready 双函数特征 */\nfunction isRouteForge(x: unknown): x is RouteForge {\n return (\n typeof x === 'object' && x !== null &&\n typeof (x as RouteForge).api === 'function' &&\n typeof (x as RouteForge).ready === 'function'\n );\n}\n","/**\n * useForge — 获取 forge 实例(Vue 特化:levelLoaded 为 Ref<boolean>)\n * @see .docs/SPEC.md §4.1.7\n *\n * 内部委托 core 的 forge.use(),仅将 levelLoaded 从 Promise<void> 替换为 Vue 响应式 Ref。\n *\n * @example\n * // 不绑定层级\n * const forge = useForge()\n * forge('admin', 'users.show', { user: 1 })\n * forge.api('admin', 'users.show')\n *\n * @example\n * // 绑定层级 — 直接调用和 api/route/url 均无需传 level\n * const forge = useForge('admin')\n * forge.level // → 'admin'\n * forge.levelLoaded // Ref<boolean>\n * forge('users.show', { user: 1 })\n * forge.route('users.show', { user: 1 })\n *\n * @example\n * // 绑定层级 + 前缀 — 路由名自动拼接\n * const forge = useForge('admin', 'users')\n * forge('show', { user: 1 }) // → forge.api('admin', 'users.show', ...)\n * forge.route('show', { user: 1 }) // → forge.route('admin', 'users.show', ...)\n */\n\nimport { inject, ref, type Ref } from 'vue';\nimport { type BoundForge, type RouteForge } from '@route-forge/core';\nimport { FORGE_INJECTION_KEY } from '../plugin.js';\n\n/** Vue 特化类型:levelLoaded 为 Ref<boolean> */\nexport type VueBoundForge = BoundForge<Ref<boolean>>;\n\nexport function useForge<L extends string>(level: L, prefix: string): VueBoundForge;\nexport function useForge<L extends string>(level: L): VueBoundForge;\nexport function useForge(): RouteForge;\nexport function useForge(level?: string, prefix?: string): RouteForge | VueBoundForge {\n const forge = inject(FORGE_INJECTION_KEY);\n if (!forge) {\n throw new Error(\n '[route-forge/vue] useForge() must be used inside an app with createRouteForgePlugin() installed',\n );\n }\n\n if (level === undefined) {\n return forge;\n }\n\n // 委托 core 的 use(),获取 BoundForge(levelLoaded 为 Promise<void>)\n const bound = forge.use(level, prefix);\n\n // 将 levelLoaded 从 Promise<void> 替换为 Ref<boolean>\n const levelLoadedRef = ref(false);\n bound.levelLoaded.then(() => {\n levelLoadedRef.value = true;\n }).catch(() => { /* 加载失败时 levelLoaded 保持 false */ });\n\n Object.defineProperty(bound, 'levelLoaded', {\n value: levelLoadedRef,\n writable: false,\n enumerable: true,\n configurable: true,\n });\n\n return bound as unknown as VueBoundForge;\n}\n","/**\n * useForgeApi:包装 forge.api(),自动管理 loading/error 状态\n * @see .docs/SPEC.md §4.1.7\n *\n * 支持:\n * - useForgeApi() — call(level, name, params)\n * - useForgeApi(level) — call(name, params),自动绑定层级\n * - useForgeApi(level, prefix) — call(suffix, params),自动绑定层级 + 拼接前缀\n *\n * 类型推断:\n * 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,\n * level / name / params 均自动推断,IDE 提供补全提示。\n *\n * pending 采用引用计数:并发多个 call 时,全部完成才置 false\n * (先完成的 call 不再把其他在途请求的 pending 提前清掉)。\n */\n\nimport type { Ref } from 'vue';\nimport { ref } from 'vue';\nimport { useForge } from './useForge.js';\nimport type {\n BoundForge,\n RouteForge,\n UseForgeApiBoundCall,\n UseForgeApiBoundReturn,\n UseForgeApiCall,\n UseForgeApiReturn,\n} from '@route-forge/core';\n\n// Vue 特化类型:pending/error 为 Ref\nexport type { UseForgeApiCall, UseForgeApiBoundCall };\nexport type UseForgeApiReturnVue = UseForgeApiReturn<Ref<boolean>, Ref<unknown>>;\nexport type UseForgeApiBoundReturnVue<L extends string> = UseForgeApiBoundReturn<L, Ref<boolean>, Ref<unknown>>;\n\n/** 不绑定层级 — call 需要传 level */\nexport function useForgeApi(): UseForgeApiReturnVue;\n/** 绑定层级 — call 无需传 level */\nexport function useForgeApi<L extends string>(level: L): UseForgeApiBoundReturnVue<L>;\n/** 绑定层级 + 前缀 — call 无需传 level,路由名自动拼接 prefix */\nexport function useForgeApi<L extends string>(level: L, prefix: string): UseForgeApiBoundReturnVue<L>;\nexport function useForgeApi(level?: string, prefix?: string): UseForgeApiReturnVue | UseForgeApiBoundReturnVue<string> {\n const bound = level !== undefined ? useForge(level, prefix as string) : undefined;\n const unbound = bound === undefined ? useForge() : undefined;\n const pending = ref(false);\n const error = ref<unknown>(null);\n // 并发计数:setup 闭包变量(组件实例生命周期存活)\n let inflight = 0;\n\n async function call(...args: unknown[]): Promise<{ data: unknown; error: unknown }> {\n inflight++;\n pending.value = true;\n error.value = null;\n try {\n // 按绑定形态分发:bound 走 BoundForge.api(name, params),unbound 走 RouteForge.api(level, name, params)\n // (窄断言替代 as any:重载签名已保证参数形状,此处仅消除联合类型/框架特化类型的分支歧义)\n const data = bound !== undefined\n ? await (bound as unknown as BoundForge).api(args[0] as string, args[1] as never)\n : await (unbound as RouteForge).api(args[0] as string, args[1] as string, args[2] as never);\n return { data, error: null };\n } catch (e) {\n error.value = e;\n return { data: undefined, error: e };\n } finally {\n inflight--;\n pending.value = inflight > 0;\n }\n }\n\n return { pending, error, call: call as unknown as UseForgeApiCall };\n}\n","/**\n * 内部 helper(非公共 API,不进包入口导出):inject forge 实例 + 缺失守卫。\n *\n * useForgeRoute / ForgeRoute / ForgeLink 统一走这里,避免裸 `as RouteForge` 强转:\n * 未安装 plugin 时报「怎么修」的指引性错误,而不是\n * `Cannot read properties of undefined (reading 'isLoaded')` 之类的晦涩堆栈。\n */\n\nimport { inject } from 'vue';\nimport { FORGE_INJECTION_KEY } from './plugin.js';\nimport type { RouteForge } from '@route-forge/core';\n\nexport function useInjectedForge(apiName: string): RouteForge {\n const forge = inject(FORGE_INJECTION_KEY);\n if (!forge) {\n throw new Error(\n `[route-forge/vue] ${apiName} must be used inside an app with createRouteForgePlugin() installed`,\n );\n }\n return forge;\n}\n","/**\n * 降级/渲染警告的统一报告器(内部实现,非公共 API,不进包入口导出):\n * - 会话级去重:同一 (component, message) 或同一渲染错误只报告一次,\n * name/params 联动输入等高频场景不刷屏\n * - enabled=false(createRouteForge({ warnings: false }))时静音\n * - __resetDegradeReportsForTests 仅供测试隔离使用\n */\n\nconst reportedKeys = new Set<string>();\nconst renderWarnKeys = new Set<string>();\n\nfunction dedupeKey(component: string, error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n return `${component}:${message}`;\n}\n\n/** 解析出错降级报告(组件层,error 级) */\nexport function reportDegrade(component: string, error: unknown, enabled = true): void {\n if (!enabled) return;\n const key = dedupeKey(component, error);\n if (reportedKeys.has(key)) return;\n reportedKeys.add(key);\n console.error(\n `%c[route-forge]%c ${component} 路由解析失败(已降级为空字符串,渲染未中断)`,\n 'color:#c0392b;font-weight:bold',\n 'color:inherit',\n error,\n );\n}\n\n/** 渲染期错误降级输出(hook 默认路径,warn 级;组件层通常以 onDegrade 升级为 error) */\nexport function reportRenderWarn(error: unknown, enabled: boolean): void {\n if (!enabled) return;\n const key = `useForgeRoute:${error instanceof Error ? error.message : String(error)}`;\n if (renderWarnKeys.has(key)) return;\n renderWarnKeys.add(key);\n console.warn(\n '%c[route-forge]%c useForgeRoute 渲染期错误(已降级为空字符串,渲染未中断)',\n 'color:#e67e22;font-weight:bold',\n 'color:inherit',\n error,\n );\n}\n\n/** 测试隔离:清空去重状态(不进公共 API) */\nexport function __resetDegradeReportsForTests(): void {\n reportedKeys.clear();\n renderWarnKeys.clear();\n}\n","/**\n * useForgeRoute:响应式 URL 生成器,内部处理 level 加载状态\n * @see .docs/SPEC.md §4.1.7\n *\n * - level 未加载时返回空字符串 ''(不抛错,模板不崩)\n * - level 加载完成后自动重新计算并返回正确 URL\n * - 路由名不存在或必填参数缺失等渲染期错误:降级为 '' 保证渲染不中断,\n * 同时以醒目的样式化 warn 输出完整错误(含堆栈)——开发期可见,生产无副作用\n * - level 为静态字符串(层级是确定性声明,不支持 `() => string` 函数形式):\n * 不支持中途动态切换 level\n * (需要另一个层级请在别的组件 / 别的 useForgeRoute 调用里分别使用,与 useForge 契约一致)\n * - 用户无需关心 levelLoaded 状态,直接用即可\n */\n\nimport { computed, type ComputedRef, getCurrentScope, onMounted, onScopeDispose, ref, watch } from 'vue';\nimport { useInjectedForge } from '../useInjectedForge.js';\nimport { reportRenderWarn } from '../degrade.js';\n\n/** 降级报告钩子:组件层(ForgeRoute/ForgeLink)用它把默认 warn 升级为 error,避免双重打印 */\nexport interface ForgeRouteDegradeHooks {\n onDegrade?: (error: unknown) => void;\n}\n\nexport function useForgeRoute(\n level: string,\n name: string | (() => string),\n params?: () => Record<string, unknown> | undefined,\n hooks?: ForgeRouteDegradeHooks,\n): ComputedRef<string> {\n return useForgeRouteState(level, name, params, hooks).href;\n}\n\n/** useForgeRoute 的三态内部形态:组件层(ForgeRoute/ForgeLink)用它区分「未加载 / 解析失败」 */\nexport interface ForgeRouteState {\n /** 生成的 URL;未加载或解析出错时为 '' */\n href: ComputedRef<string>;\n /** 解析错误(仅 level 已加载且 route() 抛错时非 null;未加载恒为 null),响应式 */\n error: ComputedRef<unknown>;\n /** level 是否已加载(区别「未加载」与「已加载但解析失败」两种空串来源),响应式 */\n isLevelLoaded: ComputedRef<boolean>;\n}\n\nexport function useForgeRouteState(\n level: string,\n name: string | (() => string),\n params?: () => Record<string, unknown> | undefined,\n hooks?: ForgeRouteDegradeHooks,\n): ForgeRouteState {\n // 运行时守卫:level 必须是静态字符串(类型收窄后防 JS 用户误用静默降级为空链接)\n if (typeof level !== 'string') {\n throw new TypeError(\n '[route-forge/vue] useForgeRoute(): level must be a static string — ' +\n 'getter form is not supported (levels are deterministic declarations; ' +\n 'create another useForgeRoute call for another level)',\n );\n }\n\n const forge = useInjectedForge('useForgeRoute()');\n\n // level 为静态字符串(层级是确定性声明):绑定即固定,不支持中途动态切换\n //(需要另一个层级请在别的组件 / 别的 useForgeRoute 调用里分别使用,与 useForge 契约一致)。\n // name / params 仍保持响应式。\n const lvl = level;\n\n // 响应式追踪该 level 的加载状态(computed 依赖此 ref 触发重算)\n const levelLoaded = ref(forge.isLoaded(lvl));\n\n if (!levelLoaded.value) {\n onMounted(() => {\n forge.load(lvl).then(() => {\n levelLoaded.value = true;\n }).catch(() => { /* 加载失败时 href 保持 '' */\n });\n });\n }\n\n // 路由数据版本:本层级被 revalidate 刷新 / invalidate 后 bump,驱动下面的 computed 重算(无刷新页面即热更新)\n const dataVersion = ref(0);\n const unsubscribe = forge.onRoutesChange((changed) => {\n if (changed === lvl) dataVersion.value++;\n });\n // 在 effect scope 内则随 scope 销毁自动退订;scope 外(如单例模块)不注册、由调用方持有 unsubscribe 自行管理\n if (getCurrentScope()) onScopeDispose(unsubscribe);\n\n // 三态同步求值(computed 纯读缓存,无副作用):\n // 未加载 → { href: '', error: null };解析失败 → { href: '', error };成功 → { href }\n const state = computed(() => {\n if (!levelLoaded.value) return { href: '', error: null as unknown };\n void dataVersion.value; // 依赖数据版本:revalidate/invalidate 后强制重算\n const n = typeof name === 'function' ? name() : name;\n const p = params ? params() : undefined;\n try {\n return { href: forge.route(lvl, n, p), error: null as unknown };\n } catch (e) {\n return { href: '', error: e as unknown };\n }\n });\n\n // 降级报告:渲染求值纯净化后,错误经 watch(组件更新前触发)输出,与 react 侧口径一致。\n // 同错会话级去重;createRouteForge({ warnings: false }) 时静音。\n watch(\n () => state.value.error,\n (err) => {\n if (err == null) return;\n if (hooks?.onDegrade) hooks.onDegrade(err);\n else reportRenderWarn(err, forge.warnings);\n },\n { immediate: true },\n );\n\n return {\n href: computed(() => state.value.href),\n error: computed(() => state.value.error),\n isLevelLoaded: computed(() => levelLoaded.value),\n };\n}\n","/**\n * ForgeRoute / ForgeLink 共享内部实现:props 定义、降级报告(转发 degrade.ts)、RouterLink 探测\n * (非公共 API,不进包入口导出)\n */\n\nimport { getCurrentInstance, type PropType } from 'vue';\n\nexport { reportDegrade, reportRenderWarn, __resetDegradeReportsForTests } from '../degrade.js';\n\n/** ForgeRoute / ForgeLink 共享 props:level 静态快照,name / params 双形态响应式 */\n// as const:防止 required: true 被宽化为 boolean,导致 defineComponent 推断出 string | undefined\nexport const forgeLinkProps = {\n /** 层级名:静态快照,setup 求值一次后固定,不支持中途切换 */\n level: { type: String, required: true },\n /** 路由名:string 或 getter 函数,保持响应式 */\n name: {\n type: [String, Function] as PropType<string | (() => string)>,\n required: true,\n },\n /** 路由参数:对象或 getter 函数,保持响应式 */\n params: {\n type: [Object, Function] as PropType<Record<string, unknown> | (() => Record<string, unknown>)>,\n required: false,\n default: undefined,\n },\n /**\n * 手动注入链接组件(组件对象或标签名字符串),注入后同时收到 `href` 与 `to` 两个 prop\n * (对齐 @route-forge/react 的 ForgeLink `as` 契约)。不传时按默认链路:\n * 探测全局 RouterLink → 原生 `<a>`。用于 RouterLink 局部注册 / 非 vue-router 链接组件场景。\n */\n as: {\n type: [Object, String, Function] as PropType<object>,\n required: false,\n default: undefined,\n },\n} as const;\n\n/** level 未加载提示:每实例仅一次(warned 为组件实例内的可变标记),避免正常加载瞬态刷屏 */\nexport function warnUnloadedOnce(component: string, level: string, warned: { value: boolean }): void {\n if (warned.value) return;\n warned.value = true;\n console.warn(\n `[route-forge] ${component}: level \"${level}\" 尚未加载,链接暂不渲染(加载完成后自动出现)`,\n );\n}\n\n/**\n * 从 app 全局组件中探测 vue-router 的 RouterLink(零依赖:不 import vue-router)。\n * vue-router 在 app.use(router) 时会把 RouterLink / router-link 注册到全局组件表;\n * 仅在父组件局部注册 RouterLink 的场景探测不到,此时降级渲染原生 <a>(README 有说明)。\n */\nexport function resolveRouterLink(): object | null {\n const inst = getCurrentInstance();\n const comps = inst?.appContext.components as Record<string, object> | undefined;\n return comps?.RouterLink ?? comps?.['router-link'] ?? null;\n}\n","/**\n * ForgeRoute:URL 生成组件(通用形态),封装 useForgeRoute 的\"先空串、后更新\"异步行为\n * @see .docs/SPEC.md §4.1.7\n *\n * - 通过作用域插槽暴露 { href, loaded },模板里自由决定渲染 <a>、RouterLink 或任意内容\n * - loaded = href !== ''(level 未加载与路由解析出错都降级为 '',正好复用该哨兵值)\n * - 三态分流:未加载 → loading 插槽;已加载但解析失败 → error 插槽(props { error },\n * 未传回落 loading);成功 → default 插槽\n * - 未加载且未传 loading 插槽时默认不渲染;每实例以 console.warn 提醒一次(防刷屏)\n * - 路由解析出错(UnknownRouteError 等)以 console.error 报告,渲染不中断\n * - level 为静态快照,name / params 保持响应式(值或 getter 函数双形态均可)\n */\n\nimport { defineComponent, type SlotsType, type VNode } from 'vue';\nimport { useInjectedForge } from '../useInjectedForge.js';\nimport { useForgeRouteState } from '../composables/useForgeRoute.js';\nimport { forgeLinkProps, reportDegrade, warnUnloadedOnce } from './shared.js';\n\nexport const ForgeRoute = defineComponent({\n name: 'ForgeRoute',\n // 根节点是用户插槽内容,框架透传 attrs 落到插槽上没有意义,显式关闭\n inheritAttrs: false,\n props: forgeLinkProps,\n slots: Object as SlotsType<{\n default?: (props: { href: string; loaded: boolean }) => VNode[];\n loading?: () => VNode[];\n /** 解析失败(路由名不存在等):props 携带错误对象;未传回落 loading 插槽 */\n error?: (props: { error: unknown }) => VNode[];\n }>,\n setup(props, { slots }) {\n const forge = useInjectedForge('ForgeRoute');\n // 统一收敛为 getter:name / params 双形态(值或函数)均保持响应式\n const nameGetter = () => (typeof props.name === 'function' ? props.name() : props.name);\n const paramsGetter = () =>\n typeof props.params === 'function' ? props.params() : props.params;\n const state = useForgeRouteState(props.level, nameGetter, paramsGetter, {\n onDegrade: (e) => reportDegrade('ForgeRoute', e, forge.warnings),\n });\n const unloadWarned = { value: false };\n\n return () => {\n const url = state.href.value;\n const loaded = url !== '';\n if (!loaded && !forge.isLoaded(props.level)) {\n warnUnloadedOnce('ForgeRoute', props.level, unloadWarned);\n }\n // 三态分流:未加载 → loading;解析失败 → error(未传回落 loading)\n if (!state.isLevelLoaded.value) return slots.loading ? slots.loading() : null;\n if (state.error.value != null) {\n return slots.error ? slots.error({ error: state.error.value }) : (slots.loading ? slots.loading() : null);\n }\n return slots.default ? slots.default({ href: url, loaded }) : null;\n };\n },\n});\n\nexport type ForgeRouteProps = InstanceType<typeof ForgeRoute>['$props'];\n","/**\n * ForgeLink:便捷链接组件,封装 useForgeRoute 的\"先空串、后更新\"异步行为\n * @see .docs/SPEC.md §4.1.7\n *\n * - loaded(href !== '')时直接渲染链接:`as` prop 显式注入的组件优先(同时收到 href+to);\n * 否则探测到 vue-router 全局注册的 RouterLink 则渲染 <RouterLink :to=\"href\">(SPA 内部跳转),\n * 再否则渲染原生 <a :href=\"href\">\n * - 三态分流:未加载 → loading 插槽;已加载但解析失败 → error 插槽(props { error },\n * 未传回落 loading);成功 → 链接\n * - 未加载且未传 loading 插槽时默认不渲染;每实例以 console.warn 提醒一次(防刷屏)\n * - 路由解析出错以 console.error 报告,渲染不中断\n * - attrs 透传到根元素(class / target / rel 等),生成的 href / to 优先于同名 attr\n * - level 为静态快照,name / params 保持响应式(值或 getter 函数双形态均可)\n */\n\nimport { defineComponent, h, type SlotsType, type VNode } from 'vue';\nimport { useInjectedForge } from '../useInjectedForge.js';\nimport { useForgeRouteState } from '../composables/useForgeRoute.js';\nimport {\n forgeLinkProps,\n reportDegrade,\n resolveRouterLink,\n warnUnloadedOnce,\n} from './shared.js';\n\nexport const ForgeLink = defineComponent({\n name: 'ForgeLink',\n // attrs 透传到 <a> / RouterLink,但 href / to 必须以组件生成的 URL 为准(显式合并)\n inheritAttrs: false,\n props: forgeLinkProps,\n slots: Object as SlotsType<{\n /** 链接文本/内容 */\n default?: () => VNode[];\n /** 未加载占位 */\n loading?: () => VNode[];\n /** 解析失败(路由名不存在等):props 携带错误对象;未传回落 loading 插槽 */\n error?: (props: { error: unknown }) => VNode[];\n }>,\n setup(props, { slots, attrs }) {\n const forge = useInjectedForge('ForgeLink');\n // 统一收敛为 getter:name / params 双形态(值或函数)均保持响应式\n const nameGetter = () => (typeof props.name === 'function' ? props.name() : props.name);\n const paramsGetter = () =>\n typeof props.params === 'function' ? props.params() : props.params;\n const state = useForgeRouteState(props.level, nameGetter, paramsGetter, {\n onDegrade: (e) => reportDegrade('ForgeLink', e, forge.warnings),\n });\n const unloadWarned = { value: false };\n // 链接组件解析:显式 as prop 优先(同时收 href+to,对齐 react 包契约);\n // 否则探测 RouterLink(app.use(router) 时全局注册,app 生命周期内不变,setup 时探测一次即可)\n const routerLink = resolveRouterLink();\n\n return () => {\n const url = state.href.value;\n const loaded = url !== '';\n if (!loaded && !forge.isLoaded(props.level)) {\n warnUnloadedOnce('ForgeLink', props.level, unloadWarned);\n }\n // 三态分流:未加载 → loading;解析失败 → error(未传回落 loading)\n if (!state.isLevelLoaded.value) return slots.loading ? slots.loading() : null;\n if (state.error.value != null) {\n return slots.error ? slots.error({ error: state.error.value }) : (slots.loading ? slots.loading() : null);\n }\n\n const children = slots.default ? slots.default() : undefined;\n if (props.as) {\n // 手动注入的链接组件:同时收到 href 与 to(对齐 @route-forge/react 的 as 契约)\n return h(\n props.as as object,\n { ...(attrs as Record<string, unknown>), to: url, href: url },\n { default: () => children },\n );\n }\n if (routerLink) {\n return h(\n routerLink,\n { ...(attrs as Record<string, unknown>), to: url },\n { default: () => children },\n );\n }\n return h('a', { ...(attrs as Record<string, unknown>), href: url }, children);\n };\n },\n});\n\nexport type ForgeLinkProps = InstanceType<typeof ForgeLink>['$props'];\n","/**\n * ForgeReady:ready 门闩组件——直接 mount 也能拿到 `ready().then(mount)` 同级的确定性。\n *\n * - ready() 未 resolve 时渲染 `fallback` 插槽(缺省不渲染任何内容),resolve 后渲染 default 插槽\n * - forge 已就绪(core `isReady()`)时同步开门,不产生多余的 fallback 首帧\n * - ready() reject:响亮 `console.error` 且保持闭门(与 `ready().then(mount).catch` 的语义对齐,\n * 不静默)——需要 reject 后继续渲染请勿使用本组件,改用 `ready().then(mount, onRejected)`\n *\n * @example\n * ```vue\n * <ForgeReady>\n * <template #fallback><Splash /></template>\n * <RouterView />\n * </ForgeReady>\n * ```\n */\n\nimport { defineComponent, ref, type SlotsType, type VNode } from 'vue';\nimport { useInjectedForge } from '../useInjectedForge.js';\n\nexport const ForgeReady = defineComponent({\n name: 'ForgeReady',\n slots: Object as SlotsType<{\n /** ready 后渲染的内容 */\n default?: () => VNode[];\n /** 门闩期间的占位 UI(缺省不渲染任何内容) */\n fallback?: () => VNode[];\n }>,\n setup(_, { slots }) {\n const forge = useInjectedForge('ForgeReady');\n const open = ref(forge.isReady());\n if (!open.value) {\n forge.ready().then(\n () => {\n open.value = true;\n },\n (err) => {\n console.error(\n '[route-forge] ForgeReady: ready() rejected — content stays gated (same as an unhandled ready().catch)',\n err,\n );\n },\n );\n }\n return () => (open.value ? slots.default?.() : (slots.fallback ? slots.fallback() : null));\n },\n});\n\nexport type ForgeReadyProps = InstanceType<typeof ForgeReady>['$props'];\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@route-forge/vue",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Route Forge 的 Vue 3 集成:插件 + composable(useForge/useForgeApi/useForgeRoute)+ 组件(ForgeRoute/ForgeLink)/ Vue 3 integration for Laravel named routes: plugin + composables (useForge / useForgeApi / useForgeRoute) + components (ForgeRoute / ForgeLink)",
5
5
  "keywords": [
6
6
  "laravel",
@@ -46,11 +46,11 @@
46
46
  "README_zh.md"
47
47
  ],
48
48
  "peerDependencies": {
49
- "@route-forge/core": "^3.0.0",
49
+ "@route-forge/core": "^3.1.0",
50
50
  "vue": "^3.3.0"
51
51
  },
52
52
  "devDependencies": {
53
- "@route-forge/core": "^3.0.0",
53
+ "@route-forge/core": "^3.1.0",
54
54
  "@vue/test-utils": "^2.4.0",
55
55
  "jsdom": "^24.0.0",
56
56
  "tsup": "^8.0.0",